aiobungie

A statically typed, asynchronous API wrapper for building clients for Bungie's API in Python.

Getting Started

aiobungie provides 3 different client interfaces to get started with, each serve a different purpose.

  • Client: is probably what you want to get started with first. It provides minimal abstraction for the REST api. Is Pythonic.
  • RESTClient: When you're building a light-weight REST backend. You can use this one. It returns JSON objects instead of dataclasses. This is considered lower-level that Client.
  • RESTPool: when you're serving a large amount of users and want to spawn a session for each. each instance of this pool returns a RESTClient.

Check either the examples or each of those objects's documentation for more information about the usage.

 1# MIT License
 2#
 3# Copyright (c) 2020 - Present nxtlo
 4#
 5# Permission is hereby granted, free of charge, to any person obtaining a copy
 6# of this software and associated documentation files (the "Software"), to deal
 7# in the Software without restriction, including without limitation the rights
 8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in all
13# copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21# SOFTWARE.
22
23"""A statically typed, asynchronous API wrapper for building clients for Bungie's API in Python.
24
25### Getting Started
26
27aiobungie provides 3 different client interfaces to get started with, each serve a different purpose.
28
29* `Client`: is probably what you want to get started with first. It provides minimal abstraction for the REST api. Is [Pythonic](https://stackoverflow.com/questions/84102/what-is-idiomatic-code#84270).
30* `RESTClient`: When you're building a light-weight REST backend. You can use this one. It returns `JSON` objects instead of `dataclasses`.
31This is considered lower-level that `Client`.
32* `RESTPool`: when you're serving a large amount of users and want to spawn a session for each. each instance of this pool returns a `RESTClient`.
33
34Check either the examples or each of those objects's documentation for more information about the usage.
35"""
36
37from __future__ import annotations
38
39from aiobungie import builders
40from aiobungie import crates
41from aiobungie import interfaces
42from aiobungie import traits
43from aiobungie import typedefs
44from aiobungie import url
45from aiobungie.client import Client
46from aiobungie.error import *
47from aiobungie.internal import iterators
48from aiobungie.internal.assets import Image
49from aiobungie.internal.enums import *
50from aiobungie.internal.factory import EmptyFactory
51from aiobungie.internal.factory import Factory
52from aiobungie.internal.iterators import *
53from aiobungie.rest import *
54
55# Activity enums
56from .crates.activity import Difficulty
57
58# Components enums
59from .crates.components import ComponentFields
60from .crates.components import ComponentPrivacy
61
62# Entity enums
63from .crates.entity import GatingScope
64from .crates.entity import ObjectiveUIStyle
65from .crates.entity import ValueUIStyle
66
67# Fireteam enums.
68from .crates.fireteams import FireteamActivity
69from .crates.fireteams import FireteamDate
70from .crates.fireteams import FireteamLanguage
71from .crates.fireteams import FireteamPlatform
72
73# Records enums
74from .crates.records import RecordState
75from .metadata import __about__
76from .metadata import __author__
77from .metadata import __docs__
78from .metadata import __email__
79from .metadata import __license__
80from .metadata import __url__
81from .metadata import __version__
82
83__all__ = [mod for mod in dir() if not mod.startswith("_")]  # type: ignore
@attrs.define(auto_exc=True)
class AiobungieError(builtins.RuntimeError):
70@attrs.define(auto_exc=True)
71class AiobungieError(RuntimeError):
72    """Base class that all other exceptions inherit from."""

Base class that all other exceptions inherit from.

AiobungieError()
2def __init__(self, ):
3    BaseException.__init__(self, )

Method generated by attrs for class AiobungieError.

Inherited Members
builtins.BaseException
with_traceback
add_note
args
@typing.final
class AmmoType(builtins.int, aiobungie.Enum):
635@typing.final
636class AmmoType(int, Enum):
637    """AN enum for Detyiny 2 ammo types."""
638
639    NONE = 0
640    PRIMARY = 1
641    SPECIAL = 2
642    HEAVY = 3

AN enum for Detyiny 2 ammo types.

NONE = <AmmoType.NONE: 0>
PRIMARY = <AmmoType.PRIMARY: 1>
SPECIAL = <AmmoType.SPECIAL: 2>
HEAVY = <AmmoType.HEAVY: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class BadRequest(aiobungie.HTTPError):
163@attrs.define(auto_exc=True)
164class BadRequest(HTTPError):
165    """An exception raised when requesting a resource with the provided data is wrong."""
166
167    url: typedefs.StrOrURL | None
168    """The URL/endpoint caused this error."""
169
170    body: typing.Any
171    """The response body."""
172
173    headers: multidict.CIMultiDictProxy[str]
174    """The response headers."""
175
176    http_status: http.HTTPStatus = attrs.field(
177        default=http.HTTPStatus.BAD_REQUEST, init=False
178    )

An exception raised when requesting a resource with the provided data is wrong.

BadRequest( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str])
2def __init__(self, message, url, body, headers):
3    self.message = message
4    self.url = url
5    self.body = body
6    self.headers = headers
7    self.http_status = attr_dict['http_status'].default
8    BaseException.__init__(self, self.message,self.url,self.body,self.headers)

Method generated by attrs for class BadRequest.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

http_status: http.HTTPStatus

The response status.

Inherited Members
HTTPError
message
builtins.BaseException
with_traceback
add_note
args
@typing.final
class ClanMemberType(builtins.int, aiobungie.Enum):
690@typing.final
691class ClanMemberType(int, Enum):
692    """An enum for bungie clan member types."""
693
694    NONE = 0
695    BEGINNER = 1
696    MEMBER = 2
697    ADMIN = 3
698    ACTING_FOUNDER = 4
699    FOUNDER = 5

An enum for bungie clan member types.

NONE = <ClanMemberType.NONE: 0>
BEGINNER = <ClanMemberType.BEGINNER: 1>
MEMBER = <ClanMemberType.MEMBER: 2>
ADMIN = <ClanMemberType.ADMIN: 3>
ACTING_FOUNDER = <ClanMemberType.ACTING_FOUNDER: 4>
FOUNDER = <ClanMemberType.FOUNDER: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Class(builtins.int, aiobungie.Enum):
466@typing.final
467class Class(int, Enum):
468    """An Enum for Destiny character classes."""
469
470    TITAN = 0
471    HUNTER = 1
472    WARLOCK = 2
473    UNKNOWN = 3

An Enum for Destiny character classes.

TITAN = <Class.TITAN: 0>
HUNTER = <Class.HUNTER: 1>
WARLOCK = <Class.WARLOCK: 2>
UNKNOWN = <Class.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
class Client(aiobungie.traits.ClientApp):
  55class Client(traits.ClientApp):
  56    """Standard Bungie API client implementation.
  57
  58    This client deserialize the REST JSON responses using `aiobungie.Factory`
  59    and returns `aiobungie.crates` Python object implementations of the responses.
  60
  61    Example
  62    -------
  63    ```py
  64    import aiobungie
  65
  66    client = aiobungie.Client('...')
  67
  68    async def main():
  69        async with client.rest:
  70            user = await client.fetch_current_user_memberships('...')
  71            print(user)
  72    ```
  73
  74    Parameters
  75    -----------
  76    token: `str`
  77        Your Bungie's API key or Token from the developer's portal.
  78
  79    Other Parameters
  80    ----------------
  81    max_retries : `int`
  82        The max retries number to retry if the request hit a `5xx` status code.
  83    client_secret : `str | None`
  84        An optional application client secret,
  85        This is only needed if you're fetching OAuth2 tokens with this client.
  86    client_id : `int | None`
  87        An optional application client id,
  88        This is only needed if you're fetching OAuth2 tokens with this client.
  89    debug: `"TRACE" | bool | int`
  90        The level of logging to enable.
  91    """
  92
  93    __slots__ = ("_rest", "_factory")
  94
  95    def __init__(
  96        self,
  97        token: str,
  98        /,
  99        *,
 100        client_secret: str | None = None,
 101        client_id: int | None = None,
 102        max_retries: int = 4,
 103        debug: typing.Literal["TRACE"] | bool | int = False,
 104    ) -> None:
 105        self._rest = rest_.RESTClient(
 106            token,
 107            client_secret=client_secret,
 108            client_id=client_id,
 109            max_retries=max_retries,
 110            debug=debug,
 111        )
 112
 113        self._factory = factory_.Factory(self)
 114
 115    @property
 116    def factory(self) -> factory_.Factory:
 117        return self._factory
 118
 119    @property
 120    def rest(self) -> interfaces.RESTInterface:
 121        return self._rest
 122
 123    @property
 124    def request(self) -> Client:
 125        return self
 126
 127    @property
 128    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 129        return self._rest.metadata
 130
 131    def run(self, fn: collections.Awaitable[typing.Any], debug: bool = False) -> None:
 132        loop = helpers.get_or_make_loop()
 133
 134        try:
 135            if not loop.is_running():
 136                loop.set_debug(debug)
 137                loop.run_until_complete(fn)
 138
 139        except Exception as exc:
 140            raise RuntimeError(f"Failed to run {fn!s}") from exc
 141
 142    # * User methods.
 143
 144    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
 145        """Fetch and return a user object of the bungie net user associated with account.
 146
 147        .. warning::
 148            This method requires OAuth2 scope and a Bearer access token.
 149
 150        Parameters
 151        ----------
 152        access_token : `str`
 153            A valid Bearer access token for the authorization.
 154
 155        Returns
 156        -------
 157        `aiobungie.crates.user.User`
 158            A user object includes the Destiny memberships and Bungie.net user.
 159        """
 160        resp = await self.rest.fetch_current_user_memberships(access_token)
 161
 162        return self.factory.deserialize_user(resp)
 163
 164    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
 165        """Fetch a Bungie user by their BungieNet id.
 166
 167        .. note::
 168            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
 169            for other memberships.
 170
 171        Parameters
 172        ----------
 173        id: `int`
 174            The user id.
 175
 176        Returns
 177        -------
 178        `aiobungie.crates.user.BungieUser`
 179            A Bungie user.
 180
 181        Raises
 182        ------
 183        `aiobungie.error.NotFound`
 184            The user was not found.
 185        """
 186        payload = await self.rest.fetch_bungie_user(id)
 187
 188        return self.factory.deserialize_bungie_user(payload)
 189
 190    async def search_users(
 191        self, name: str, /
 192    ) -> iterators.Iterator[user.SearchableDestinyUser]:
 193        """Search for players and return all players that matches the same name.
 194
 195        Parameters
 196        ----------
 197        name : `str`
 198            The user name.
 199
 200        Returns
 201        -------
 202        `aiobungie.Iterator[aiobungie.crates.SearchableDestinyUser]`
 203            A sequence of the found users with this name.
 204        """
 205        payload = await self.rest.search_users(name)
 206
 207        return iterators.Iterator(
 208            [
 209                self.factory.deserialize_searched_user(user)
 210                for user in payload["searchResults"]
 211            ]
 212        )
 213
 214    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
 215        """Fetch all available user themes.
 216
 217        Returns
 218        -------
 219        `collections.Sequence[aiobungie.crates.user.UserThemes]`
 220            A sequence of user themes.
 221        """
 222        data = await self.rest.fetch_user_themes()
 223
 224        return self.factory.deserialize_user_themes(data)
 225
 226    async def fetch_hard_types(
 227        self,
 228        credential: int,
 229        type: enums.CredentialType | int = enums.CredentialType.STEAMID,
 230        /,
 231    ) -> user.HardLinkedMembership:
 232        """Gets any hard linked membership given a credential.
 233        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
 234        Cross Save aware.
 235
 236        Parameters
 237        ----------
 238        credential: `int`
 239            A valid SteamID64
 240        type: `aiobungie.CredentialType`
 241            The credential type. This must not be changed
 242            Since its only credential that works "currently"
 243
 244        Returns
 245        -------
 246        `aiobungie.crates.user.HardLinkedMembership`
 247            Information about the hard linked data.
 248        """
 249
 250        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
 251
 252        return user.HardLinkedMembership(
 253            id=int(payload["membershipId"]),
 254            type=enums.MembershipType(payload["membershipType"]),
 255            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
 256        )
 257
 258    async def fetch_membership_from_id(
 259        self,
 260        id: int,
 261        /,
 262        type: enums.MembershipType | int = enums.MembershipType.NONE,
 263    ) -> user.User:
 264        """Fetch Bungie user's memberships from their id.
 265
 266        Notes
 267        -----
 268        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
 269        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
 270        see `aiobungie.crates.user.DestinyMembership` for more details.
 271        * If you only want the bungie user. Consider using `Client.fetch_user` method.
 272
 273        Parameters
 274        ----------
 275        id : `int`
 276            The user's id.
 277        type : `aiobungie.MembershipType`
 278            The user's membership type.
 279
 280        Returns
 281        -------
 282        `aiobungie.crates.User`
 283            A Bungie user with their membership types.
 284
 285        Raises
 286        ------
 287        aiobungie.NotFound
 288            The requested user was not found.
 289        """
 290        payload = await self.rest.fetch_membership_from_id(id, type)
 291
 292        return self.factory.deserialize_user(payload)
 293
 294    async def fetch_user_credentials(
 295        self, access_token: str, membership_id: int, /
 296    ) -> collections.Sequence[user.UserCredentials]:
 297        """Fetch an array of credential types attached to the requested account.
 298
 299        .. note::
 300            This method require OAuth2 Bearer access token.
 301
 302        Parameters
 303        ----------
 304        access_token : `str`
 305            The bearer access token associated with the bungie account.
 306        membership_id : `int`
 307            The id of the membership to return.
 308
 309        Returns
 310        -------
 311        `collections.Sequence[aiobungie.crates.UserCredentials]`
 312            A sequence of the attached user credentials.
 313
 314        Raises
 315        ------
 316        `aiobungie.Unauthorized`
 317            The access token was wrong or no access token passed.
 318        """
 319        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
 320
 321        return self.factory.deserialize_user_credentials(resp)
 322
 323    # * Destiny 2.
 324
 325    async def fetch_profile(
 326        self,
 327        member_id: int,
 328        type: enums.MembershipType | int,
 329        components: collections.Sequence[enums.ComponentType],
 330        auth: str | None = None,
 331    ) -> components.Component:
 332        """
 333        Fetch a bungie profile passing components to the request.
 334
 335        Parameters
 336        ----------
 337        member_id: `int`
 338            The member's id.
 339        type: `aiobungie.MembershipType`
 340            A valid membership type.
 341        components : `collections.Sequence[aiobungie.ComponentType]`
 342            List of profile components to collect and return.
 343
 344        Other Parameters
 345        ----------------
 346        auth : `str | None`
 347            A Bearer access_token to make the request with.
 348            This is optional and limited to components that only requires an Authorization token.
 349
 350        Returns
 351        --------
 352        `aiobungie.crates.Component`
 353            A Destiny 2 player profile with its components.
 354            Only passed components will be available if they exists. Otherwise they will be `None`
 355
 356        Raises
 357        ------
 358        `aiobungie.MembershipTypeError`
 359            The provided membership type was invalid.
 360        """
 361        data = await self.rest.fetch_profile(member_id, type, components, auth)
 362        return self.factory.deserialize_components(data)
 363
 364    async def fetch_linked_profiles(
 365        self,
 366        member_id: int,
 367        member_type: enums.MembershipType | int,
 368        /,
 369        *,
 370        all: bool = False,
 371    ) -> profile.LinkedProfile:
 372        """Returns a summary information about all profiles linked to the requested member.
 373
 374        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
 375
 376        .. note::
 377            It will only return linked accounts whose linkages you are allowed to view.
 378
 379        Parameters
 380        ----------
 381        member_id : `int`
 382            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
 383        member_type : `aiobungie.MembershipType`
 384            The type for the membership whose linked Destiny account you want to return.
 385
 386        Other Parameters
 387        ----------------
 388        all : `bool`
 389            If provided and set to `True`, All memberships regardless
 390            of whether they're obscured by overrides will be returned,
 391
 392            If provided and set to `False`, Only available memberships will be returned.
 393            The default for this is `False`.
 394
 395        Returns
 396        -------
 397        `aiobungie.crates.profile.LinkedProfile`
 398            A linked profile object.
 399        """
 400        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
 401
 402        return self.factory.deserialize_linked_profiles(resp)
 403
 404    async def fetch_membership(
 405        self,
 406        name: str,
 407        code: int,
 408        /,
 409        type: enums.MembershipType | int = enums.MembershipType.ALL,
 410    ) -> collections.Sequence[user.DestinyMembership]:
 411        """Fetch a Destiny 2 player's memberships.
 412
 413        Parameters
 414        -----------
 415        name: `str`
 416            The unique Bungie player name.
 417        code : `int`
 418            The unique Bungie display name code.
 419        type: `aiobungie.internal.enums.MembershipType`
 420            The player's membership type, e,g. XBOX, STEAM, PSN
 421
 422        Returns
 423        --------
 424        `collections.Sequence[aiobungie.crates.DestinyMembership]`
 425            A sequence of the found Destiny 2 player memberships.
 426            An empty sequence will be returned if no one found.
 427
 428        Raises
 429        ------
 430        `aiobungie.MembershipTypeError`
 431            The provided membership type was invalid.
 432        """
 433        resp = await self.rest.fetch_membership(name, code, type)
 434
 435        return self.factory.deserialize_destiny_memberships(resp)
 436
 437    async def fetch_character(
 438        self,
 439        member_id: int,
 440        membership_type: enums.MembershipType | int,
 441        character_id: int,
 442        components: collections.Sequence[enums.ComponentType],
 443        auth: str | None = None,
 444    ) -> components.CharacterComponent:
 445        """Fetch a Destiny 2 character.
 446
 447        Parameters
 448        ----------
 449        member_id: `int`
 450            A valid bungie member id.
 451        character_id: `int`
 452            The Destiny character id to retrieve.
 453        membership_type: `aiobungie.internal.enums.MembershipType`
 454            The member's membership type.
 455        components: `collections.Sequence[aiobungie.ComponentType]`
 456            Multiple arguments of character components to collect and return.
 457
 458        Other Parameters
 459        ----------------
 460        auth : `str | None`
 461            A Bearer access_token to make the request with.
 462            This is optional and limited to components that only requires an Authorization token.
 463
 464        Returns
 465        -------
 466        `aiobungie.crates.CharacterComponent`
 467            A Bungie character component.
 468
 469        `aiobungie.MembershipTypeError`
 470            The provided membership type was invalid.
 471        """
 472        resp = await self.rest.fetch_character(
 473            member_id, membership_type, character_id, components, auth
 474        )
 475
 476        return self.factory.deserialize_character_component(resp)
 477
 478    async def fetch_unique_weapon_history(
 479        self,
 480        membership_id: int,
 481        character_id: int,
 482        membership_type: enums.MembershipType | int,
 483    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
 484        """Fetch details about unique weapon usage for a character. Includes all exotics.
 485
 486        Parameters
 487        ----------
 488        membership_id : `int`
 489            The Destiny user membership id.
 490        character_id : `int`
 491            The character id to retrieve.
 492        membership_type : `aiobungie.aiobungie.MembershipType | int`
 493            The Destiny user's membership type.
 494
 495        Returns
 496        -------
 497        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
 498            A sequence of the weapon's extended values.
 499        """
 500        resp = await self._rest.fetch_unique_weapon_history(
 501            membership_id, character_id, membership_type
 502        )
 503
 504        return tuple(
 505            self._factory.deserialize_extended_weapon_values(weapon)
 506            for weapon in resp["weapons"]
 507        )
 508
 509    # * Destiny 2 Activities.
 510
 511    async def fetch_activities(
 512        self,
 513        member_id: int,
 514        character_id: int,
 515        mode: enums.GameMode | int,
 516        *,
 517        membership_type: enums.MembershipType | int = enums.MembershipType.ALL,
 518        page: int = 0,
 519        limit: int = 250,
 520    ) -> iterators.Iterator[activity.Activity]:
 521        """Fetch a Destiny 2 activity for the specified character id.
 522
 523        Parameters
 524        ----------
 525        member_id: `int`
 526            The user id that starts with `4611`.
 527        character_id: `int`
 528            The id of the character to retrieve the activities for.
 529        mode: `aiobungie.aiobungie.internal.enums.GameMode | int`
 530            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
 531
 532        Other Parameters
 533        ----------------
 534        membership_type: `aiobungie.internal.enums.MembershipType`
 535            The Member ship type, if nothing was passed than it will return all.
 536        page: int
 537            The page number. Default is `0`
 538        limit: int
 539            Limit the returned result. Default is `250`.
 540
 541        Returns
 542        -------
 543        `aiobungie.Iterator[aiobungie.crates.Activity]`
 544            An iterator of the player's activities.
 545
 546        Raises
 547        ------
 548        `aiobungie.MembershipTypeError`
 549            The provided membership type was invalid.
 550        """
 551        resp = await self.rest.fetch_activities(
 552            member_id,
 553            character_id,
 554            mode,
 555            membership_type=membership_type,
 556            page=page,
 557            limit=limit,
 558        )
 559
 560        return self.factory.deserialize_activities(resp)
 561
 562    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
 563        """Fetch a post activity details.
 564
 565        Parameters
 566        ----------
 567        instance_id: `int`
 568            The activity instance id.
 569
 570        Returns
 571        -------
 572        `aiobungie.crates.PostActivity`
 573           A post activity object.
 574        """
 575        resp = await self.rest.fetch_post_activity(instance_id)
 576
 577        return self.factory.deserialize_post_activity(resp)
 578
 579    async def fetch_aggregated_activity_stats(
 580        self,
 581        character_id: int,
 582        membership_id: int,
 583        membership_type: enums.MembershipType | int,
 584    ) -> iterators.Iterator[activity.AggregatedActivity]:
 585        """Fetch aggregated activity stats for a character.
 586
 587        Parameters
 588        ----------
 589        character_id: `int`
 590            The id of the character to retrieve the activities for.
 591        membership_id: `int`
 592            The id of the user that started with `4611`.
 593        membership_type: `aiobungie.internal.enums.MembershipType`
 594            The Member ship type.
 595
 596        Returns
 597        -------
 598        `aiobungie.Iterator[aiobungie.crates.AggregatedActivity]`
 599            An iterator of the player's activities.
 600
 601        Raises
 602        ------
 603        `aiobungie.MembershipTypeError`
 604            The provided membership type was invalid.
 605        """
 606        resp = await self.rest.fetch_aggregated_activity_stats(
 607            character_id, membership_id, membership_type
 608        )
 609
 610        return self.factory.deserialize_aggregated_activities(resp)
 611
 612    # * Destiny 2 Clans or GroupsV2.
 613
 614    async def fetch_clan_from_id(
 615        self,
 616        id: int,
 617        /,
 618        access_token: str | None = None,
 619    ) -> clans.Clan:
 620        """Fetch a Bungie Clan by its id.
 621
 622        Parameters
 623        -----------
 624        id: `int`
 625            The clan id.
 626
 627        Returns
 628        --------
 629        `aiobungie.crates.Clan`
 630            An Bungie clan.
 631
 632        Raises
 633        ------
 634        `aiobungie.NotFound`
 635            The clan was not found.
 636        """
 637        resp = await self.rest.fetch_clan_from_id(id, access_token)
 638
 639        return self.factory.deserialize_clan(resp)
 640
 641    async def fetch_clan(
 642        self,
 643        name: str,
 644        /,
 645        access_token: str | None = None,
 646        *,
 647        type: enums.GroupType | int = enums.GroupType.CLAN,
 648    ) -> clans.Clan:
 649        """Fetch a Clan by its name.
 650        This method will return the first clan found with given name.
 651
 652        Parameters
 653        ----------
 654        name: `str`
 655            The clan name
 656
 657        Other Parameters
 658        ----------------
 659        access_token : `str | None`
 660            An optional access token to make the request with.
 661
 662            If the token was bound to a member of the clan,
 663            This field `aiobungie.crates.Clan.current_user_membership` will be available
 664            and will return the membership of the user who made this request.
 665        type : `aiobungie.GroupType`
 666            The group type, Default is aiobungie.GroupType.CLAN.
 667
 668        Returns
 669        -------
 670        `aiobungie.crates.Clan`
 671            A Bungie clan.
 672
 673        Raises
 674        ------
 675        `aiobungie.NotFound`
 676            The clan was not found.
 677        """
 678        resp = await self.rest.fetch_clan(name, access_token, type=type)
 679
 680        return self.factory.deserialize_clan(resp)
 681
 682    async def fetch_clan_conversations(
 683        self, clan_id: int, /
 684    ) -> collections.Sequence[clans.ClanConversation]:
 685        """Fetch the conversations/chat channels of the given clan id.
 686
 687        Parameters
 688        ----------
 689        clan_id : `int`
 690            The clan id.
 691
 692        Returns
 693        `collections.Sequence[aiobungie.crates.ClanConversation]`
 694            A sequence of the clan chat channels.
 695        """
 696        resp = await self.rest.fetch_clan_conversations(clan_id)
 697
 698        return self.factory.deserialize_clan_conversations(resp)
 699
 700    async def fetch_clan_admins(
 701        self, clan_id: int, /
 702    ) -> iterators.Iterator[clans.ClanMember]:
 703        """Fetch the clan founder and admins.
 704
 705        Parameters
 706        ----------
 707        clan_id : `int`
 708            The clan id.
 709
 710        Returns
 711        -------
 712        `aiobungie.Iterator[aiobungie.crates.ClanMember]`
 713            An iterator over the found clan admins and founder.
 714
 715        Raises
 716        ------
 717        `aiobungie.NotFound`
 718            The requested clan was not found.
 719        """
 720        resp = await self.rest.fetch_clan_admins(clan_id)
 721
 722        return self.factory.deserialize_clan_members(resp)
 723
 724    async def fetch_groups_for_member(
 725        self,
 726        member_id: int,
 727        member_type: enums.MembershipType | int,
 728        /,
 729        *,
 730        filter: int = 0,
 731        group_type: enums.GroupType = enums.GroupType.CLAN,
 732    ) -> collections.Sequence[clans.GroupMember]:
 733        """Fetch information about the groups that a given member has joined.
 734
 735        Parameters
 736        ----------
 737        member_id : `int`
 738            The member's id
 739        member_type : `aiobungie.MembershipType`
 740            The member's membership type.
 741
 742        Other Parameters
 743        ----------------
 744        filter : `int`
 745            Filter apply to list of joined groups. This Default to `0`
 746        group_type : `aiobungie.GroupType`
 747            The group's type.
 748            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 749
 750        Returns
 751        -------
 752        `collections.Sequence[aiobungie.crates.GroupMember]`
 753            A sequence of joined groups for the fetched member.
 754        """
 755        resp = await self.rest.fetch_groups_for_member(
 756            member_id, member_type, filter=filter, group_type=group_type
 757        )
 758
 759        return tuple(
 760            self.factory.deserialize_group_member(group) for group in resp["results"]
 761        )
 762
 763    async def fetch_potential_groups_for_member(
 764        self,
 765        member_id: int,
 766        member_type: enums.MembershipType | int,
 767        /,
 768        *,
 769        filter: int = 0,
 770        group_type: enums.GroupType | int = enums.GroupType.CLAN,
 771    ) -> collections.Sequence[clans.GroupMember]:
 772        """Fetch the potential groups for a clan member.
 773
 774        Parameters
 775        ----------
 776        member_id : `int`
 777            The member's id
 778        member_type : `aiobungie.aiobungie.MembershipType | int`
 779            The member's membership type.
 780
 781        Other Parameters
 782        ----------------
 783        filter : `int`
 784            Filter apply to list of joined groups. This Default to `0`
 785        group_type : `aiobungie.aiobungie.GroupType | int`
 786            The group's type.
 787            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 788
 789        Returns
 790        -------
 791        `collections.Sequence[aiobungie.crates.GroupMember]`
 792            A sequence of joined potential groups for the fetched member.
 793        """
 794        resp = await self.rest.fetch_potential_groups_for_member(
 795            member_id, member_type, filter=filter, group_type=group_type
 796        )
 797
 798        return tuple(
 799            self.factory.deserialize_group_member(group) for group in resp["results"]
 800        )
 801
 802    async def fetch_clan_members(
 803        self,
 804        clan_id: int,
 805        /,
 806        *,
 807        name: str | None = None,
 808        type: enums.MembershipType | int = enums.MembershipType.NONE,
 809    ) -> iterators.Iterator[clans.ClanMember]:
 810        """Fetch Bungie clan members.
 811
 812        Parameters
 813        ----------
 814        clan_id : `int`
 815            The clans id
 816
 817        Other Parameters
 818        ----------------
 819        name : `str | None`
 820            If provided, Only players matching this name will be returned.
 821        type : `aiobungie.MembershipType`
 822            An optional clan member's membership type.
 823            This parameter is used to filter the returned results
 824            by the provided membership, For an example XBox memberships only,
 825            Otherwise will return all memberships.
 826
 827        Returns
 828        -------
 829        `aiobungie.Iterator[aiobungie.crates.ClanMember]`
 830            An iterator over the bungie clan members.
 831
 832        Raises
 833        ------
 834        `aiobungie.NotFound`
 835            The clan was not found.
 836        """
 837        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
 838
 839        return self.factory.deserialize_clan_members(resp)
 840
 841    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
 842        """Fetch the clan banners.
 843
 844        Returns
 845        -------
 846        `collections.Sequence[aiobungie.crates.ClanBanner]`
 847            A sequence of the clan banners.
 848        """
 849        resp = await self.rest.fetch_clan_banners()
 850
 851        return self.factory.deserialize_clan_banners(resp)
 852
 853    # This method is required to be here since it deserialize the clan.
 854    async def kick_clan_member(
 855        self,
 856        access_token: str,
 857        /,
 858        group_id: int,
 859        membership_id: int,
 860        membership_type: enums.MembershipType | int,
 861    ) -> clans.Clan:
 862        """Kick a member from the clan.
 863
 864        .. note::
 865            This request requires OAuth2: oauth2: `AdminGroups` scope.
 866
 867        Parameters
 868        ----------
 869        access_token : `str`
 870            The bearer access token associated with the bungie account.
 871        group_id: `int`
 872            The group id.
 873        membership_id : `int`
 874            The member id to kick.
 875        membership_type : `aiobungie.aiobungie.MembershipType | int`
 876            The member's membership type.
 877
 878        Returns
 879        -------
 880        `aiobungie.crates.clan.Clan`
 881            The clan that the member was kicked from.
 882        """
 883        resp = await self.rest.kick_clan_member(
 884            access_token,
 885            group_id=group_id,
 886            membership_id=membership_id,
 887            membership_type=membership_type,
 888        )
 889
 890        return self.factory.deserialize_clan(resp)
 891
 892    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
 893        """Fetch a Bungie clan's weekly reward state.
 894
 895        Parameters
 896        ----------
 897        clan_id : `int`
 898            The clan's id.
 899
 900        Returns
 901        -------
 902        `aiobungie.crates.Milestone`
 903            A runtime status of the clan's milestone data.
 904        """
 905
 906        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
 907
 908        return self.factory.deserialize_milestone(resp)
 909
 910    # * Destiny 2 Entities aka Definitions.
 911
 912    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
 913        """Fetch a static inventory item entity given a its hash.
 914
 915        Parameters
 916        ----------
 917        hash: `int`
 918            Inventory item's hash.
 919
 920        Returns
 921        -------
 922        `aiobungie.crates.InventoryEntity`
 923            A bungie inventory item.
 924        """
 925        resp = await self.rest.fetch_inventory_item(hash)
 926
 927        return self.factory.deserialize_inventory_entity(resp)
 928
 929    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
 930        """Fetch a Destiny objective entity given a its hash.
 931
 932        Parameters
 933        ----------
 934        hash: `int`
 935            objective's hash.
 936
 937        Returns
 938        -------
 939        `aiobungie.crates.ObjectiveEntity`
 940            An objective entity item.
 941        """
 942        resp = await self.rest.fetch_objective_entity(hash)
 943
 944        return self.factory.deserialize_objective_entity(resp)
 945
 946    async def search_entities(
 947        self, name: str, entity_type: str, *, page: int = 0
 948    ) -> iterators.Iterator[entity.SearchableEntity]:
 949        """Search for Destiny2 entities given a name and its type.
 950
 951        Parameters
 952        ----------
 953        name : `str`
 954            The name of the entity, i.e., Thunderlord, One thousand voices.
 955        entity_type : `str`
 956            The type of the entity, AKA Definition,
 957            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
 958
 959        Other Parameters
 960        ----------------
 961        page : `int`
 962            An optional page to return. Default to 0.
 963
 964        Returns
 965        -------
 966        `aiobungie.Iterator[aiobungie.crates.SearchableEntity]`
 967            An iterator over the found results matching the provided name.
 968        """
 969        resp = await self.rest.search_entities(name, entity_type, page=page)
 970
 971        return self.factory.deserialize_inventory_results(resp)
 972
 973    # Fireteams
 974
 975    async def fetch_fireteams(
 976        self,
 977        activity_type: fireteams.FireteamActivity | int,
 978        *,
 979        platform: fireteams.FireteamPlatform | int = fireteams.FireteamPlatform.ANY,
 980        language: fireteams.FireteamLanguage | str = fireteams.FireteamLanguage.ALL,
 981        date_range: int = 0,
 982        page: int = 0,
 983        slots_filter: int = 0,
 984    ) -> collections.Sequence[fireteams.Fireteam]:
 985        """Fetch public Bungie fireteams with open slots.
 986
 987        Parameters
 988        ----------
 989        activity_type : `aiobungie.aiobungie.crates.FireteamActivity | int`
 990            The fireteam activity type.
 991
 992        Other Parameters
 993        ----------------
 994        platform : `aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int`
 995            If this is provided. Then the results will be filtered with the given platform.
 996            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
 997        language : `aiobungie.crates.fireteams.FireteamLanguage | str`
 998            A locale language to filter the used language in that fireteam.
 999            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1000        date_range : `int`
1001            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1002        page : `int`
1003            The page number. By default its `0` which returns all available activities.
1004        slots_filter : `int`
1005            Filter the returned fireteams based on available slots. Default is `0`
1006
1007        Returns
1008        -------
1009        `collections.Sequence[fireteams.Fireteam]`
1010            A sequence of `aiobungie.crates.Fireteam`.
1011        """
1012
1013        resp = await self.rest.fetch_fireteams(
1014            activity_type,
1015            platform=platform,
1016            language=language,
1017            date_range=date_range,
1018            page=page,
1019            slots_filter=slots_filter,
1020        )
1021
1022        return self.factory.deserialize_fireteams(resp)
1023
1024    async def fetch_available_clan_fireteams(
1025        self,
1026        access_token: str,
1027        group_id: int,
1028        activity_type: fireteams.FireteamActivity | int,
1029        *,
1030        platform: fireteams.FireteamPlatform | int,
1031        language: fireteams.FireteamLanguage | str,
1032        date_range: int = 0,
1033        page: int = 0,
1034        public_only: bool = False,
1035        slots_filter: int = 0,
1036    ) -> collections.Sequence[fireteams.Fireteam]:
1037        """Fetch a clan's fireteams with open slots.
1038
1039        .. note::
1040            This method requires OAuth2: ReadGroups scope.
1041
1042        Parameters
1043        ----------
1044        access_token : `str`
1045            The bearer access token associated with the bungie account.
1046        group_id : `int`
1047            The group/clan id of the fireteam.
1048        activity_type : `aiobungie.aiobungie.crates.FireteamActivity | int`
1049            The fireteam activity type.
1050
1051        Other Parameters
1052        ----------------
1053        platform : `aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int`
1054            If this is provided. Then the results will be filtered with the given platform.
1055            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1056        language : `aiobungie.crates.fireteams.FireteamLanguage | str`
1057            A locale language to filter the used language in that fireteam.
1058            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1059        date_range : `int`
1060            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1061        page : `int`
1062            The page number. By default its `0` which returns all available activities.
1063        public_only: `bool`
1064            If set to True, Then only public fireteams will be returned.
1065        slots_filter : `int`
1066            Filter the returned fireteams based on available slots. Default is `0`
1067
1068        Returns
1069        -------
1070        `collections.Sequence[aiobungie.crates.Fireteam]`
1071            A sequence of  fireteams found in the clan.
1072            `None` will be returned if nothing was found.
1073        """
1074        resp = await self.rest.fetch_available_clan_fireteams(
1075            access_token,
1076            group_id,
1077            activity_type,
1078            platform=platform,
1079            language=language,
1080            date_range=date_range,
1081            page=page,
1082            public_only=public_only,
1083            slots_filter=slots_filter,
1084        )
1085
1086        return self.factory.deserialize_fireteams(resp)
1087
1088    async def fetch_clan_fireteam(
1089        self, access_token: str, fireteam_id: int, group_id: int
1090    ) -> fireteams.AvailableFireteam:
1091        """Fetch a specific clan fireteam.
1092
1093        .. note::
1094            This method requires OAuth2: ReadGroups scope.
1095
1096        Parameters
1097        ----------
1098        access_token : `str`
1099            The bearer access token associated with the bungie account.
1100        group_id : `int`
1101            The group/clan id to fetch the fireteam from.
1102        fireteam_id : `int`
1103            The fireteam id to fetch.
1104
1105        Returns
1106        -------
1107        `aiobungie.crates.AvailableFireteam`
1108            A sequence of available fireteams objects.
1109        """
1110        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1111
1112        return self.factory.deserialize_available_fireteam(resp)
1113
1114    async def fetch_my_clan_fireteams(
1115        self,
1116        access_token: str,
1117        group_id: int,
1118        *,
1119        include_closed: bool = True,
1120        platform: fireteams.FireteamPlatform | int,
1121        language: fireteams.FireteamLanguage | str,
1122        filtered: bool = True,
1123        page: int = 0,
1124    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1125        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1126
1127        .. note::
1128            This method requires OAuth2: ReadGroups scope.
1129
1130        Parameters
1131        ----------
1132        access_token : str
1133            The bearer access token associated with the bungie account.
1134        group_id : int
1135            The group/clan id to fetch.
1136
1137        Other Parameters
1138        ----------------
1139        include_closed : `bool`
1140            If provided and set to True, It will also return closed fireteams.
1141            If provided and set to False, It will only return public fireteams. Default is True.
1142        platform : aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int
1143            If this is provided. Then the results will be filtered with the given platform.
1144            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1145        language : `aiobungie.crates.fireteams.FireteamLanguage | str`
1146            A locale language to filter the used language in that fireteam.
1147            Defaults to aiobungie.crates.FireteamLanguage.ALL
1148        filtered : `bool`
1149            If set to True, it will filter by clan. Otherwise not. Default is True.
1150        page : `int`
1151            The page number. By default its 0 which returns all available activities.
1152
1153        Returns
1154        -------
1155        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1156            A sequence of available fireteams objects if exists. else `None` will be returned.
1157        """
1158        resp = await self.rest.fetch_my_clan_fireteams(
1159            access_token,
1160            group_id,
1161            include_closed=include_closed,
1162            platform=platform,
1163            language=language,
1164            filtered=filtered,
1165            page=page,
1166        )
1167
1168        return self.factory.deserialize_available_fireteams(resp)
1169
1170    # Friends and social.
1171
1172    async def fetch_friends(
1173        self, access_token: str, /
1174    ) -> collections.Sequence[friends.Friend]:
1175        """Fetch bungie friend list.
1176
1177        .. note::
1178            This requests OAuth2: ReadUserData scope.
1179
1180        Parameters
1181        -----------
1182        access_token : `str`
1183            The bearer access token associated with the bungie account.
1184
1185        Returns
1186        -------
1187        `collections.Sequence[aiobungie.crates.Friend]`
1188            A sequence of the friends associated with that access token.
1189        """
1190
1191        resp = await self.rest.fetch_friends(access_token)
1192
1193        return self.factory.deserialize_friends(resp)
1194
1195    async def fetch_friend_requests(
1196        self, access_token: str, /
1197    ) -> friends.FriendRequestView:
1198        """Fetch pending bungie friend requests queue.
1199
1200        .. note::
1201            This requests OAuth2: ReadUserData scope.
1202
1203        Parameters
1204        -----------
1205        access_token : `str`
1206            The bearer access token associated with the bungie account.
1207
1208        Returns
1209        -------
1210        `aiobungie.crates.FriendRequestView`
1211            A friend requests view of that associated access token.
1212        """
1213
1214        resp = await self.rest.fetch_friend_requests(access_token)
1215
1216        return self.factory.deserialize_friend_requests(resp)
1217
1218    # Applications and Developer portal.
1219
1220    async def fetch_application(self, appid: int, /) -> application.Application:
1221        """Fetch a Bungie application.
1222
1223        Parameters
1224        -----------
1225        appid: `int`
1226            The application id.
1227
1228        Returns
1229        --------
1230        `aiobungie.crates.Application`
1231            A Bungie application.
1232        """
1233        resp = await self.rest.fetch_application(appid)
1234
1235        return self.factory.deserialize_app(resp)
1236
1237    # Milestones
1238
1239    async def fetch_public_milestone_content(
1240        self, milestone_hash: int, /
1241    ) -> milestones.MilestoneContent:
1242        """Fetch the milestone content given its hash.
1243
1244        Parameters
1245        ----------
1246        milestone_hash : `int`
1247            The milestone hash.
1248
1249        Returns
1250        -------
1251        `aiobungie.crates.milestones.MilestoneContent`
1252            A milestone content object.
1253        """
1254        ...
1255        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1256        return self.factory.deserialize_public_milestone_content(resp)

Standard Bungie API client implementation.

This client deserialize the REST JSON responses using aiobungie.Factory and returns aiobungie.crates Python object implementations of the responses.

Example
import aiobungie

client = aiobungie.Client('...')

async def main():
    async with client.rest:
        user = await client.fetch_current_user_memberships('...')
        print(user)
Parameters
  • token (str): Your Bungie's API key or Token from the developer's portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • client_secret (str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • debug ("TRACE" | bool | int): The level of logging to enable.
Client( token: str, /, *, client_secret: str | None = None, client_id: int | None = None, max_retries: int = 4, debug: Union[Literal['TRACE'], bool, int] = False)
 95    def __init__(
 96        self,
 97        token: str,
 98        /,
 99        *,
100        client_secret: str | None = None,
101        client_id: int | None = None,
102        max_retries: int = 4,
103        debug: typing.Literal["TRACE"] | bool | int = False,
104    ) -> None:
105        self._rest = rest_.RESTClient(
106            token,
107            client_secret=client_secret,
108            client_id=client_id,
109            max_retries=max_retries,
110            debug=debug,
111        )
112
113        self._factory = factory_.Factory(self)
factory: Factory
115    @property
116    def factory(self) -> factory_.Factory:
117        return self._factory

Returns the marshalling factory for the client.

rest: aiobungie.interfaces.rest.RESTInterface
119    @property
120    def rest(self) -> interfaces.RESTInterface:
121        return self._rest

Returns the REST client for the this client.

request: Client
123    @property
124    def request(self) -> Client:
125        return self

A readonly ClientApp instance used for external requests.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]
127    @property
128    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
129        return self._rest.metadata

A mutable mapping storage for the user's needs.

def run( self, fn: collections.abc.Awaitable[typing.Any], debug: bool = False) -> None:
131    def run(self, fn: collections.Awaitable[typing.Any], debug: bool = False) -> None:
132        loop = helpers.get_or_make_loop()
133
134        try:
135            if not loop.is_running():
136                loop.set_debug(debug)
137                loop.run_until_complete(fn)
138
139        except Exception as exc:
140            raise RuntimeError(f"Failed to run {fn!s}") from exc

Runs a coroutine function until its complete.

This is equivalent to asyncio.get_event_loop().run_until_complete(...)

Parameters
  • fn (collections.Awaitable[Any]): The async function to run.
  • debug (bool): Either to enable asyncio debug or not. Disabled by default.
Example
async def main() -> None:
    await fetch(...)

# Run the coroutine.
client.run(main())
async def fetch_current_user_memberships(self, access_token: str, /) -> aiobungie.crates.user.User:
144    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
145        """Fetch and return a user object of the bungie net user associated with account.
146
147        .. warning::
148            This method requires OAuth2 scope and a Bearer access token.
149
150        Parameters
151        ----------
152        access_token : `str`
153            A valid Bearer access token for the authorization.
154
155        Returns
156        -------
157        `aiobungie.crates.user.User`
158            A user object includes the Destiny memberships and Bungie.net user.
159        """
160        resp = await self.rest.fetch_current_user_memberships(access_token)
161
162        return self.factory.deserialize_user(resp)

Fetch and return a user object of the bungie net user associated with account.

This method requires OAuth2 scope and a Bearer access token.

Parameters
  • access_token (str): A valid Bearer access token for the authorization.
Returns
  • aiobungie.crates.user.User: A user object includes the Destiny memberships and Bungie.net user.
async def fetch_bungie_user(self, id: int, /) -> aiobungie.crates.user.BungieUser:
164    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
165        """Fetch a Bungie user by their BungieNet id.
166
167        .. note::
168            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
169            for other memberships.
170
171        Parameters
172        ----------
173        id: `int`
174            The user id.
175
176        Returns
177        -------
178        `aiobungie.crates.user.BungieUser`
179            A Bungie user.
180
181        Raises
182        ------
183        `aiobungie.error.NotFound`
184            The user was not found.
185        """
186        payload = await self.rest.fetch_bungie_user(id)
187
188        return self.factory.deserialize_bungie_user(payload)

Fetch a Bungie user by their BungieNet id.

This returns a Bungie user membership only. Take a look at Client.fetch_membership_from_id for other memberships.

Parameters
  • id (int): The user id.
Returns
  • aiobungie.crates.user.BungieUser: A Bungie user.
Raises
async def search_users( self, name: str, /) -> Iterator[aiobungie.crates.user.SearchableDestinyUser]:
190    async def search_users(
191        self, name: str, /
192    ) -> iterators.Iterator[user.SearchableDestinyUser]:
193        """Search for players and return all players that matches the same name.
194
195        Parameters
196        ----------
197        name : `str`
198            The user name.
199
200        Returns
201        -------
202        `aiobungie.Iterator[aiobungie.crates.SearchableDestinyUser]`
203            A sequence of the found users with this name.
204        """
205        payload = await self.rest.search_users(name)
206
207        return iterators.Iterator(
208            [
209                self.factory.deserialize_searched_user(user)
210                for user in payload["searchResults"]
211            ]
212        )

Search for players and return all players that matches the same name.

Parameters
  • name (str): The user name.
Returns
async def fetch_user_themes(self) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
214    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
215        """Fetch all available user themes.
216
217        Returns
218        -------
219        `collections.Sequence[aiobungie.crates.user.UserThemes]`
220            A sequence of user themes.
221        """
222        data = await self.rest.fetch_user_themes()
223
224        return self.factory.deserialize_user_themes(data)

Fetch all available user themes.

Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of user themes.
async def fetch_hard_types( self, credential: int, type: CredentialType | int = <CredentialType.STEAMID: 12>, /) -> aiobungie.crates.user.HardLinkedMembership:
226    async def fetch_hard_types(
227        self,
228        credential: int,
229        type: enums.CredentialType | int = enums.CredentialType.STEAMID,
230        /,
231    ) -> user.HardLinkedMembership:
232        """Gets any hard linked membership given a credential.
233        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
234        Cross Save aware.
235
236        Parameters
237        ----------
238        credential: `int`
239            A valid SteamID64
240        type: `aiobungie.CredentialType`
241            The credential type. This must not be changed
242            Since its only credential that works "currently"
243
244        Returns
245        -------
246        `aiobungie.crates.user.HardLinkedMembership`
247            Information about the hard linked data.
248        """
249
250        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
251
252        return user.HardLinkedMembership(
253            id=int(payload["membershipId"]),
254            type=enums.MembershipType(payload["membershipType"]),
255            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
256        )

Gets any hard linked membership given a credential. Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
  • credential (int): A valid SteamID64
  • type (aiobungie.CredentialType): The credential type. This must not be changed Since its only credential that works "currently"
Returns
  • aiobungie.crates.user.HardLinkedMembership: Information about the hard linked data.
async def fetch_membership_from_id( self, id: int, /, type: MembershipType | int = <MembershipType.NONE: 0>) -> aiobungie.crates.user.User:
258    async def fetch_membership_from_id(
259        self,
260        id: int,
261        /,
262        type: enums.MembershipType | int = enums.MembershipType.NONE,
263    ) -> user.User:
264        """Fetch Bungie user's memberships from their id.
265
266        Notes
267        -----
268        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
269        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
270        see `aiobungie.crates.user.DestinyMembership` for more details.
271        * If you only want the bungie user. Consider using `Client.fetch_user` method.
272
273        Parameters
274        ----------
275        id : `int`
276            The user's id.
277        type : `aiobungie.MembershipType`
278            The user's membership type.
279
280        Returns
281        -------
282        `aiobungie.crates.User`
283            A Bungie user with their membership types.
284
285        Raises
286        ------
287        aiobungie.NotFound
288            The requested user was not found.
289        """
290        payload = await self.rest.fetch_membership_from_id(id, type)
291
292        return self.factory.deserialize_user(payload)

Fetch Bungie user's memberships from their id.

Notes
  • This returns both BungieNet membership and a sequence of the player's DestinyMemberships Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, see aiobungie.crates.user.DestinyMembership for more details.
  • If you only want the bungie user. Consider using Client.fetch_user method.
Parameters
Returns
Raises
async def fetch_user_credentials( self, access_token: str, membership_id: int, /) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
294    async def fetch_user_credentials(
295        self, access_token: str, membership_id: int, /
296    ) -> collections.Sequence[user.UserCredentials]:
297        """Fetch an array of credential types attached to the requested account.
298
299        .. note::
300            This method require OAuth2 Bearer access token.
301
302        Parameters
303        ----------
304        access_token : `str`
305            The bearer access token associated with the bungie account.
306        membership_id : `int`
307            The id of the membership to return.
308
309        Returns
310        -------
311        `collections.Sequence[aiobungie.crates.UserCredentials]`
312            A sequence of the attached user credentials.
313
314        Raises
315        ------
316        `aiobungie.Unauthorized`
317            The access token was wrong or no access token passed.
318        """
319        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
320
321        return self.factory.deserialize_user_credentials(resp)

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def fetch_profile( self, member_id: int, type: MembershipType | int, components: collections.abc.Sequence[ComponentType], auth: str | None = None) -> aiobungie.crates.components.Component:
325    async def fetch_profile(
326        self,
327        member_id: int,
328        type: enums.MembershipType | int,
329        components: collections.Sequence[enums.ComponentType],
330        auth: str | None = None,
331    ) -> components.Component:
332        """
333        Fetch a bungie profile passing components to the request.
334
335        Parameters
336        ----------
337        member_id: `int`
338            The member's id.
339        type: `aiobungie.MembershipType`
340            A valid membership type.
341        components : `collections.Sequence[aiobungie.ComponentType]`
342            List of profile components to collect and return.
343
344        Other Parameters
345        ----------------
346        auth : `str | None`
347            A Bearer access_token to make the request with.
348            This is optional and limited to components that only requires an Authorization token.
349
350        Returns
351        --------
352        `aiobungie.crates.Component`
353            A Destiny 2 player profile with its components.
354            Only passed components will be available if they exists. Otherwise they will be `None`
355
356        Raises
357        ------
358        `aiobungie.MembershipTypeError`
359            The provided membership type was invalid.
360        """
361        data = await self.rest.fetch_profile(member_id, type, components, auth)
362        return self.factory.deserialize_components(data)

Fetch a bungie profile passing components to the request.

Parameters
Other Parameters
  • auth (str | None): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
  • aiobungie.crates.Component: A Destiny 2 player profile with its components. Only passed components will be available if they exists. Otherwise they will be None
Raises
async def fetch_linked_profiles( self, member_id: int, member_type: MembershipType | int, /, *, all: bool = False) -> aiobungie.crates.profile.LinkedProfile:
364    async def fetch_linked_profiles(
365        self,
366        member_id: int,
367        member_type: enums.MembershipType | int,
368        /,
369        *,
370        all: bool = False,
371    ) -> profile.LinkedProfile:
372        """Returns a summary information about all profiles linked to the requested member.
373
374        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
375
376        .. note::
377            It will only return linked accounts whose linkages you are allowed to view.
378
379        Parameters
380        ----------
381        member_id : `int`
382            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
383        member_type : `aiobungie.MembershipType`
384            The type for the membership whose linked Destiny account you want to return.
385
386        Other Parameters
387        ----------------
388        all : `bool`
389            If provided and set to `True`, All memberships regardless
390            of whether they're obscured by overrides will be returned,
391
392            If provided and set to `False`, Only available memberships will be returned.
393            The default for this is `False`.
394
395        Returns
396        -------
397        `aiobungie.crates.profile.LinkedProfile`
398            A linked profile object.
399        """
400        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
401
402        return self.factory.deserialize_linked_profiles(resp)

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
  • member_id (int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
  • member_type (aiobungie.MembershipType): The type for the membership whose linked Destiny account you want to return.
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether they're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
  • aiobungie.crates.profile.LinkedProfile: A linked profile object.
async def fetch_membership( self, name: str, code: int, /, type: MembershipType | int = <MembershipType.ALL: -1>) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
404    async def fetch_membership(
405        self,
406        name: str,
407        code: int,
408        /,
409        type: enums.MembershipType | int = enums.MembershipType.ALL,
410    ) -> collections.Sequence[user.DestinyMembership]:
411        """Fetch a Destiny 2 player's memberships.
412
413        Parameters
414        -----------
415        name: `str`
416            The unique Bungie player name.
417        code : `int`
418            The unique Bungie display name code.
419        type: `aiobungie.internal.enums.MembershipType`
420            The player's membership type, e,g. XBOX, STEAM, PSN
421
422        Returns
423        --------
424        `collections.Sequence[aiobungie.crates.DestinyMembership]`
425            A sequence of the found Destiny 2 player memberships.
426            An empty sequence will be returned if no one found.
427
428        Raises
429        ------
430        `aiobungie.MembershipTypeError`
431            The provided membership type was invalid.
432        """
433        resp = await self.rest.fetch_membership(name, code, type)
434
435        return self.factory.deserialize_destiny_memberships(resp)

Fetch a Destiny 2 player's memberships.

Parameters
  • name (str): The unique Bungie player name.
  • code (int): The unique Bungie display name code.
  • type (MembershipType): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
Raises
async def fetch_character( self, member_id: int, membership_type: MembershipType | int, character_id: int, components: collections.abc.Sequence[ComponentType], auth: str | None = None) -> aiobungie.crates.components.CharacterComponent:
437    async def fetch_character(
438        self,
439        member_id: int,
440        membership_type: enums.MembershipType | int,
441        character_id: int,
442        components: collections.Sequence[enums.ComponentType],
443        auth: str | None = None,
444    ) -> components.CharacterComponent:
445        """Fetch a Destiny 2 character.
446
447        Parameters
448        ----------
449        member_id: `int`
450            A valid bungie member id.
451        character_id: `int`
452            The Destiny character id to retrieve.
453        membership_type: `aiobungie.internal.enums.MembershipType`
454            The member's membership type.
455        components: `collections.Sequence[aiobungie.ComponentType]`
456            Multiple arguments of character components to collect and return.
457
458        Other Parameters
459        ----------------
460        auth : `str | None`
461            A Bearer access_token to make the request with.
462            This is optional and limited to components that only requires an Authorization token.
463
464        Returns
465        -------
466        `aiobungie.crates.CharacterComponent`
467            A Bungie character component.
468
469        `aiobungie.MembershipTypeError`
470            The provided membership type was invalid.
471        """
472        resp = await self.rest.fetch_character(
473            member_id, membership_type, character_id, components, auth
474        )
475
476        return self.factory.deserialize_character_component(resp)

Fetch a Destiny 2 character.

Parameters
  • member_id (int): A valid bungie member id.
  • character_id (int): The Destiny character id to retrieve.
  • membership_type (MembershipType): The member's membership type.
  • components (collections.Sequence[aiobungie.ComponentType]): Multiple arguments of character components to collect and return.
Other Parameters
  • auth (str | None): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: MembershipType | int) -> collections.abc.Sequence[aiobungie.crates.activity.ExtendedWeaponValues]:
478    async def fetch_unique_weapon_history(
479        self,
480        membership_id: int,
481        character_id: int,
482        membership_type: enums.MembershipType | int,
483    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
484        """Fetch details about unique weapon usage for a character. Includes all exotics.
485
486        Parameters
487        ----------
488        membership_id : `int`
489            The Destiny user membership id.
490        character_id : `int`
491            The character id to retrieve.
492        membership_type : `aiobungie.aiobungie.MembershipType | int`
493            The Destiny user's membership type.
494
495        Returns
496        -------
497        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
498            A sequence of the weapon's extended values.
499        """
500        resp = await self._rest.fetch_unique_weapon_history(
501            membership_id, character_id, membership_type
502        )
503
504        return tuple(
505            self._factory.deserialize_extended_weapon_values(weapon)
506            for weapon in resp["weapons"]
507        )

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
  • membership_id (int): The Destiny user membership id.
  • character_id (int): The character id to retrieve.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The Destiny user's membership type.
Returns
async def fetch_activities( self, member_id: int, character_id: int, mode: GameMode | int, *, membership_type: MembershipType | int = <MembershipType.ALL: -1>, page: int = 0, limit: int = 250) -> Iterator[aiobungie.crates.activity.Activity]:
511    async def fetch_activities(
512        self,
513        member_id: int,
514        character_id: int,
515        mode: enums.GameMode | int,
516        *,
517        membership_type: enums.MembershipType | int = enums.MembershipType.ALL,
518        page: int = 0,
519        limit: int = 250,
520    ) -> iterators.Iterator[activity.Activity]:
521        """Fetch a Destiny 2 activity for the specified character id.
522
523        Parameters
524        ----------
525        member_id: `int`
526            The user id that starts with `4611`.
527        character_id: `int`
528            The id of the character to retrieve the activities for.
529        mode: `aiobungie.aiobungie.internal.enums.GameMode | int`
530            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
531
532        Other Parameters
533        ----------------
534        membership_type: `aiobungie.internal.enums.MembershipType`
535            The Member ship type, if nothing was passed than it will return all.
536        page: int
537            The page number. Default is `0`
538        limit: int
539            Limit the returned result. Default is `250`.
540
541        Returns
542        -------
543        `aiobungie.Iterator[aiobungie.crates.Activity]`
544            An iterator of the player's activities.
545
546        Raises
547        ------
548        `aiobungie.MembershipTypeError`
549            The provided membership type was invalid.
550        """
551        resp = await self.rest.fetch_activities(
552            member_id,
553            character_id,
554            mode,
555            membership_type=membership_type,
556            page=page,
557            limit=limit,
558        )
559
560        return self.factory.deserialize_activities(resp)

Fetch a Destiny 2 activity for the specified character id.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve the activities for.
  • mode (aiobungie.aiobungie.internal.enums.GameMode | int): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
  • membership_type (MembershipType): The Member ship type, if nothing was passed than it will return all.
  • page (int): The page number. Default is 0
  • limit (int): Limit the returned result. Default is 250.
Returns
Raises
async def fetch_post_activity(self, instance_id: int, /) -> aiobungie.crates.activity.PostActivity:
562    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
563        """Fetch a post activity details.
564
565        Parameters
566        ----------
567        instance_id: `int`
568            The activity instance id.
569
570        Returns
571        -------
572        `aiobungie.crates.PostActivity`
573           A post activity object.
574        """
575        resp = await self.rest.fetch_post_activity(instance_id)
576
577        return self.factory.deserialize_post_activity(resp)

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: MembershipType | int) -> Iterator[aiobungie.crates.activity.AggregatedActivity]:
579    async def fetch_aggregated_activity_stats(
580        self,
581        character_id: int,
582        membership_id: int,
583        membership_type: enums.MembershipType | int,
584    ) -> iterators.Iterator[activity.AggregatedActivity]:
585        """Fetch aggregated activity stats for a character.
586
587        Parameters
588        ----------
589        character_id: `int`
590            The id of the character to retrieve the activities for.
591        membership_id: `int`
592            The id of the user that started with `4611`.
593        membership_type: `aiobungie.internal.enums.MembershipType`
594            The Member ship type.
595
596        Returns
597        -------
598        `aiobungie.Iterator[aiobungie.crates.AggregatedActivity]`
599            An iterator of the player's activities.
600
601        Raises
602        ------
603        `aiobungie.MembershipTypeError`
604            The provided membership type was invalid.
605        """
606        resp = await self.rest.fetch_aggregated_activity_stats(
607            character_id, membership_id, membership_type
608        )
609
610        return self.factory.deserialize_aggregated_activities(resp)

Fetch aggregated activity stats for a character.

Parameters
  • character_id (int): The id of the character to retrieve the activities for.
  • membership_id (int): The id of the user that started with 4611.
  • membership_type (MembershipType): The Member ship type.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: str | None = None) -> aiobungie.crates.clans.Clan:
614    async def fetch_clan_from_id(
615        self,
616        id: int,
617        /,
618        access_token: str | None = None,
619    ) -> clans.Clan:
620        """Fetch a Bungie Clan by its id.
621
622        Parameters
623        -----------
624        id: `int`
625            The clan id.
626
627        Returns
628        --------
629        `aiobungie.crates.Clan`
630            An Bungie clan.
631
632        Raises
633        ------
634        `aiobungie.NotFound`
635            The clan was not found.
636        """
637        resp = await self.rest.fetch_clan_from_id(id, access_token)
638
639        return self.factory.deserialize_clan(resp)

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Returns
Raises
async def fetch_clan( self, name: str, /, access_token: str | None = None, *, type: GroupType | int = <GroupType.CLAN: 1>) -> aiobungie.crates.clans.Clan:
641    async def fetch_clan(
642        self,
643        name: str,
644        /,
645        access_token: str | None = None,
646        *,
647        type: enums.GroupType | int = enums.GroupType.CLAN,
648    ) -> clans.Clan:
649        """Fetch a Clan by its name.
650        This method will return the first clan found with given name.
651
652        Parameters
653        ----------
654        name: `str`
655            The clan name
656
657        Other Parameters
658        ----------------
659        access_token : `str | None`
660            An optional access token to make the request with.
661
662            If the token was bound to a member of the clan,
663            This field `aiobungie.crates.Clan.current_user_membership` will be available
664            and will return the membership of the user who made this request.
665        type : `aiobungie.GroupType`
666            The group type, Default is aiobungie.GroupType.CLAN.
667
668        Returns
669        -------
670        `aiobungie.crates.Clan`
671            A Bungie clan.
672
673        Raises
674        ------
675        `aiobungie.NotFound`
676            The clan was not found.
677        """
678        resp = await self.rest.fetch_clan(name, access_token, type=type)
679
680        return self.factory.deserialize_clan(resp)

Fetch a Clan by its name. This method will return the first clan found with given name.

Parameters
  • name (str): The clan name
Other Parameters
Returns
Raises
async def fetch_clan_conversations( self, clan_id: int, /) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
682    async def fetch_clan_conversations(
683        self, clan_id: int, /
684    ) -> collections.Sequence[clans.ClanConversation]:
685        """Fetch the conversations/chat channels of the given clan id.
686
687        Parameters
688        ----------
689        clan_id : `int`
690            The clan id.
691
692        Returns
693        `collections.Sequence[aiobungie.crates.ClanConversation]`
694            A sequence of the clan chat channels.
695        """
696        resp = await self.rest.fetch_clan_conversations(clan_id)
697
698        return self.factory.deserialize_clan_conversations(resp)

Fetch the conversations/chat channels of the given clan id.

Parameters
async def fetch_clan_admins( self, clan_id: int, /) -> Iterator[aiobungie.crates.clans.ClanMember]:
700    async def fetch_clan_admins(
701        self, clan_id: int, /
702    ) -> iterators.Iterator[clans.ClanMember]:
703        """Fetch the clan founder and admins.
704
705        Parameters
706        ----------
707        clan_id : `int`
708            The clan id.
709
710        Returns
711        -------
712        `aiobungie.Iterator[aiobungie.crates.ClanMember]`
713            An iterator over the found clan admins and founder.
714
715        Raises
716        ------
717        `aiobungie.NotFound`
718            The requested clan was not found.
719        """
720        resp = await self.rest.fetch_clan_admins(clan_id)
721
722        return self.factory.deserialize_clan_members(resp)

Fetch the clan founder and admins.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_groups_for_member( self, member_id: int, member_type: MembershipType | int, /, *, filter: int = 0, group_type: GroupType = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
724    async def fetch_groups_for_member(
725        self,
726        member_id: int,
727        member_type: enums.MembershipType | int,
728        /,
729        *,
730        filter: int = 0,
731        group_type: enums.GroupType = enums.GroupType.CLAN,
732    ) -> collections.Sequence[clans.GroupMember]:
733        """Fetch information about the groups that a given member has joined.
734
735        Parameters
736        ----------
737        member_id : `int`
738            The member's id
739        member_type : `aiobungie.MembershipType`
740            The member's membership type.
741
742        Other Parameters
743        ----------------
744        filter : `int`
745            Filter apply to list of joined groups. This Default to `0`
746        group_type : `aiobungie.GroupType`
747            The group's type.
748            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
749
750        Returns
751        -------
752        `collections.Sequence[aiobungie.crates.GroupMember]`
753            A sequence of joined groups for the fetched member.
754        """
755        resp = await self.rest.fetch_groups_for_member(
756            member_id, member_type, filter=filter, group_type=group_type
757        )
758
759        return tuple(
760            self.factory.deserialize_group_member(group) for group in resp["results"]
761        )

Fetch information about the groups that a given member has joined.

Parameters
Other Parameters
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: MembershipType | int, /, *, filter: int = 0, group_type: GroupType | int = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
763    async def fetch_potential_groups_for_member(
764        self,
765        member_id: int,
766        member_type: enums.MembershipType | int,
767        /,
768        *,
769        filter: int = 0,
770        group_type: enums.GroupType | int = enums.GroupType.CLAN,
771    ) -> collections.Sequence[clans.GroupMember]:
772        """Fetch the potential groups for a clan member.
773
774        Parameters
775        ----------
776        member_id : `int`
777            The member's id
778        member_type : `aiobungie.aiobungie.MembershipType | int`
779            The member's membership type.
780
781        Other Parameters
782        ----------------
783        filter : `int`
784            Filter apply to list of joined groups. This Default to `0`
785        group_type : `aiobungie.aiobungie.GroupType | int`
786            The group's type.
787            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
788
789        Returns
790        -------
791        `collections.Sequence[aiobungie.crates.GroupMember]`
792            A sequence of joined potential groups for the fetched member.
793        """
794        resp = await self.rest.fetch_potential_groups_for_member(
795            member_id, member_type, filter=filter, group_type=group_type
796        )
797
798        return tuple(
799            self.factory.deserialize_group_member(group) for group in resp["results"]
800        )

Fetch the potential groups for a clan member.

Parameters
  • member_id (int): The member's id
  • member_type (aiobungie.aiobungie.MembershipType | int): The member's membership type.
Other Parameters
  • filter (int): Filter apply to list of joined groups. This Default to 0
  • group_type (aiobungie.aiobungie.GroupType | int): The group's type. This is always set to aiobungie.GroupType.CLAN and should not be changed.
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: str | None = None, type: MembershipType | int = <MembershipType.NONE: 0>) -> Iterator[aiobungie.crates.clans.ClanMember]:
802    async def fetch_clan_members(
803        self,
804        clan_id: int,
805        /,
806        *,
807        name: str | None = None,
808        type: enums.MembershipType | int = enums.MembershipType.NONE,
809    ) -> iterators.Iterator[clans.ClanMember]:
810        """Fetch Bungie clan members.
811
812        Parameters
813        ----------
814        clan_id : `int`
815            The clans id
816
817        Other Parameters
818        ----------------
819        name : `str | None`
820            If provided, Only players matching this name will be returned.
821        type : `aiobungie.MembershipType`
822            An optional clan member's membership type.
823            This parameter is used to filter the returned results
824            by the provided membership, For an example XBox memberships only,
825            Otherwise will return all memberships.
826
827        Returns
828        -------
829        `aiobungie.Iterator[aiobungie.crates.ClanMember]`
830            An iterator over the bungie clan members.
831
832        Raises
833        ------
834        `aiobungie.NotFound`
835            The clan was not found.
836        """
837        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
838
839        return self.factory.deserialize_clan_members(resp)

Fetch Bungie clan members.

Parameters
  • clan_id (int): The clans id
Other Parameters
  • name (str | None): If provided, Only players matching this name will be returned.
  • type (aiobungie.MembershipType): An optional clan member's membership type. This parameter is used to filter the returned results by the provided membership, For an example XBox memberships only, Otherwise will return all memberships.
Returns
Raises
async def fetch_clan_banners(self) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
841    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
842        """Fetch the clan banners.
843
844        Returns
845        -------
846        `collections.Sequence[aiobungie.crates.ClanBanner]`
847            A sequence of the clan banners.
848        """
849        resp = await self.rest.fetch_clan_banners()
850
851        return self.factory.deserialize_clan_banners(resp)

Fetch the clan banners.

Returns
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: MembershipType | int) -> aiobungie.crates.clans.Clan:
854    async def kick_clan_member(
855        self,
856        access_token: str,
857        /,
858        group_id: int,
859        membership_id: int,
860        membership_type: enums.MembershipType | int,
861    ) -> clans.Clan:
862        """Kick a member from the clan.
863
864        .. note::
865            This request requires OAuth2: oauth2: `AdminGroups` scope.
866
867        Parameters
868        ----------
869        access_token : `str`
870            The bearer access token associated with the bungie account.
871        group_id: `int`
872            The group id.
873        membership_id : `int`
874            The member id to kick.
875        membership_type : `aiobungie.aiobungie.MembershipType | int`
876            The member's membership type.
877
878        Returns
879        -------
880        `aiobungie.crates.clan.Clan`
881            The clan that the member was kicked from.
882        """
883        resp = await self.rest.kick_clan_member(
884            access_token,
885            group_id=group_id,
886            membership_id=membership_id,
887            membership_type=membership_type,
888        )
889
890        return self.factory.deserialize_clan(resp)

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The member's membership type.
Returns
  • aiobungie.crates.clan.Clan: The clan that the member was kicked from.
async def fetch_clan_weekly_rewards(self, clan_id: int) -> aiobungie.crates.milestones.Milestone:
892    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
893        """Fetch a Bungie clan's weekly reward state.
894
895        Parameters
896        ----------
897        clan_id : `int`
898            The clan's id.
899
900        Returns
901        -------
902        `aiobungie.crates.Milestone`
903            A runtime status of the clan's milestone data.
904        """
905
906        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
907
908        return self.factory.deserialize_milestone(resp)

Fetch a Bungie clan's weekly reward state.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_inventory_item(self, hash: int, /) -> aiobungie.crates.entity.InventoryEntity:
912    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
913        """Fetch a static inventory item entity given a its hash.
914
915        Parameters
916        ----------
917        hash: `int`
918            Inventory item's hash.
919
920        Returns
921        -------
922        `aiobungie.crates.InventoryEntity`
923            A bungie inventory item.
924        """
925        resp = await self.rest.fetch_inventory_item(hash)
926
927        return self.factory.deserialize_inventory_entity(resp)

Fetch a static inventory item entity given a its hash.

Parameters
  • hash (int): Inventory item's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> aiobungie.crates.entity.ObjectiveEntity:
929    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
930        """Fetch a Destiny objective entity given a its hash.
931
932        Parameters
933        ----------
934        hash: `int`
935            objective's hash.
936
937        Returns
938        -------
939        `aiobungie.crates.ObjectiveEntity`
940            An objective entity item.
941        """
942        resp = await self.rest.fetch_objective_entity(hash)
943
944        return self.factory.deserialize_objective_entity(resp)

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> Iterator[aiobungie.crates.entity.SearchableEntity]:
946    async def search_entities(
947        self, name: str, entity_type: str, *, page: int = 0
948    ) -> iterators.Iterator[entity.SearchableEntity]:
949        """Search for Destiny2 entities given a name and its type.
950
951        Parameters
952        ----------
953        name : `str`
954            The name of the entity, i.e., Thunderlord, One thousand voices.
955        entity_type : `str`
956            The type of the entity, AKA Definition,
957            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
958
959        Other Parameters
960        ----------------
961        page : `int`
962            An optional page to return. Default to 0.
963
964        Returns
965        -------
966        `aiobungie.Iterator[aiobungie.crates.SearchableEntity]`
967            An iterator over the found results matching the provided name.
968        """
969        resp = await self.rest.search_entities(name, entity_type, page=page)
970
971        return self.factory.deserialize_inventory_results(resp)

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition for emblems, weapons, and other inventory items.
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_fireteams( self, activity_type: FireteamActivity | int, *, platform: FireteamPlatform | int = <FireteamPlatform.ANY: 0>, language: FireteamLanguage | str = <FireteamLanguage.ALL: >, date_range: int = 0, page: int = 0, slots_filter: int = 0) -> collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]:
 975    async def fetch_fireteams(
 976        self,
 977        activity_type: fireteams.FireteamActivity | int,
 978        *,
 979        platform: fireteams.FireteamPlatform | int = fireteams.FireteamPlatform.ANY,
 980        language: fireteams.FireteamLanguage | str = fireteams.FireteamLanguage.ALL,
 981        date_range: int = 0,
 982        page: int = 0,
 983        slots_filter: int = 0,
 984    ) -> collections.Sequence[fireteams.Fireteam]:
 985        """Fetch public Bungie fireteams with open slots.
 986
 987        Parameters
 988        ----------
 989        activity_type : `aiobungie.aiobungie.crates.FireteamActivity | int`
 990            The fireteam activity type.
 991
 992        Other Parameters
 993        ----------------
 994        platform : `aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int`
 995            If this is provided. Then the results will be filtered with the given platform.
 996            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
 997        language : `aiobungie.crates.fireteams.FireteamLanguage | str`
 998            A locale language to filter the used language in that fireteam.
 999            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1000        date_range : `int`
1001            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1002        page : `int`
1003            The page number. By default its `0` which returns all available activities.
1004        slots_filter : `int`
1005            Filter the returned fireteams based on available slots. Default is `0`
1006
1007        Returns
1008        -------
1009        `collections.Sequence[fireteams.Fireteam]`
1010            A sequence of `aiobungie.crates.Fireteam`.
1011        """
1012
1013        resp = await self.rest.fetch_fireteams(
1014            activity_type,
1015            platform=platform,
1016            language=language,
1017            date_range=date_range,
1018            page=page,
1019            slots_filter=slots_filter,
1020        )
1021
1022        return self.factory.deserialize_fireteams(resp)

Fetch public Bungie fireteams with open slots.

Parameters
  • activity_type (aiobungie.aiobungie.crates.FireteamActivity | int): The fireteam activity type.
Other Parameters
  • platform (aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_available_clan_fireteams( self, access_token: str, group_id: int, activity_type: FireteamActivity | int, *, platform: FireteamPlatform | int, language: FireteamLanguage | str, date_range: int = 0, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]:
1024    async def fetch_available_clan_fireteams(
1025        self,
1026        access_token: str,
1027        group_id: int,
1028        activity_type: fireteams.FireteamActivity | int,
1029        *,
1030        platform: fireteams.FireteamPlatform | int,
1031        language: fireteams.FireteamLanguage | str,
1032        date_range: int = 0,
1033        page: int = 0,
1034        public_only: bool = False,
1035        slots_filter: int = 0,
1036    ) -> collections.Sequence[fireteams.Fireteam]:
1037        """Fetch a clan's fireteams with open slots.
1038
1039        .. note::
1040            This method requires OAuth2: ReadGroups scope.
1041
1042        Parameters
1043        ----------
1044        access_token : `str`
1045            The bearer access token associated with the bungie account.
1046        group_id : `int`
1047            The group/clan id of the fireteam.
1048        activity_type : `aiobungie.aiobungie.crates.FireteamActivity | int`
1049            The fireteam activity type.
1050
1051        Other Parameters
1052        ----------------
1053        platform : `aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int`
1054            If this is provided. Then the results will be filtered with the given platform.
1055            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1056        language : `aiobungie.crates.fireteams.FireteamLanguage | str`
1057            A locale language to filter the used language in that fireteam.
1058            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1059        date_range : `int`
1060            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1061        page : `int`
1062            The page number. By default its `0` which returns all available activities.
1063        public_only: `bool`
1064            If set to True, Then only public fireteams will be returned.
1065        slots_filter : `int`
1066            Filter the returned fireteams based on available slots. Default is `0`
1067
1068        Returns
1069        -------
1070        `collections.Sequence[aiobungie.crates.Fireteam]`
1071            A sequence of  fireteams found in the clan.
1072            `None` will be returned if nothing was found.
1073        """
1074        resp = await self.rest.fetch_available_clan_fireteams(
1075            access_token,
1076            group_id,
1077            activity_type,
1078            platform=platform,
1079            language=language,
1080            date_range=date_range,
1081            page=page,
1082            public_only=public_only,
1083            slots_filter=slots_filter,
1084        )
1085
1086        return self.factory.deserialize_fireteams(resp)

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.aiobungie.crates.FireteamActivity | int): The fireteam activity type.
Other Parameters
  • platform (aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to 0.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
  • collections.Sequence[aiobungie.crates.Fireteam]: A sequence of fireteams found in the clan. None will be returned if nothing was found.
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> aiobungie.crates.fireteams.AvailableFireteam:
1088    async def fetch_clan_fireteam(
1089        self, access_token: str, fireteam_id: int, group_id: int
1090    ) -> fireteams.AvailableFireteam:
1091        """Fetch a specific clan fireteam.
1092
1093        .. note::
1094            This method requires OAuth2: ReadGroups scope.
1095
1096        Parameters
1097        ----------
1098        access_token : `str`
1099            The bearer access token associated with the bungie account.
1100        group_id : `int`
1101            The group/clan id to fetch the fireteam from.
1102        fireteam_id : `int`
1103            The fireteam id to fetch.
1104
1105        Returns
1106        -------
1107        `aiobungie.crates.AvailableFireteam`
1108            A sequence of available fireteams objects.
1109        """
1110        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1111
1112        return self.factory.deserialize_available_fireteam(resp)

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: FireteamPlatform | int, language: FireteamLanguage | str, filtered: bool = True, page: int = 0) -> collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]:
1114    async def fetch_my_clan_fireteams(
1115        self,
1116        access_token: str,
1117        group_id: int,
1118        *,
1119        include_closed: bool = True,
1120        platform: fireteams.FireteamPlatform | int,
1121        language: fireteams.FireteamLanguage | str,
1122        filtered: bool = True,
1123        page: int = 0,
1124    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1125        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1126
1127        .. note::
1128            This method requires OAuth2: ReadGroups scope.
1129
1130        Parameters
1131        ----------
1132        access_token : str
1133            The bearer access token associated with the bungie account.
1134        group_id : int
1135            The group/clan id to fetch.
1136
1137        Other Parameters
1138        ----------------
1139        include_closed : `bool`
1140            If provided and set to True, It will also return closed fireteams.
1141            If provided and set to False, It will only return public fireteams. Default is True.
1142        platform : aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int
1143            If this is provided. Then the results will be filtered with the given platform.
1144            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1145        language : `aiobungie.crates.fireteams.FireteamLanguage | str`
1146            A locale language to filter the used language in that fireteam.
1147            Defaults to aiobungie.crates.FireteamLanguage.ALL
1148        filtered : `bool`
1149            If set to True, it will filter by clan. Otherwise not. Default is True.
1150        page : `int`
1151            The page number. By default its 0 which returns all available activities.
1152
1153        Returns
1154        -------
1155        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1156            A sequence of available fireteams objects if exists. else `None` will be returned.
1157        """
1158        resp = await self.rest.fetch_my_clan_fireteams(
1159            access_token,
1160            group_id,
1161            include_closed=include_closed,
1162            platform=platform,
1163            language=language,
1164            filtered=filtered,
1165            page=page,
1166        )
1167
1168        return self.factory.deserialize_available_fireteams(resp)

A method that's similar to fetch_fireteams but requires OAuth2.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_friends( self, access_token: str, /) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
1172    async def fetch_friends(
1173        self, access_token: str, /
1174    ) -> collections.Sequence[friends.Friend]:
1175        """Fetch bungie friend list.
1176
1177        .. note::
1178            This requests OAuth2: ReadUserData scope.
1179
1180        Parameters
1181        -----------
1182        access_token : `str`
1183            The bearer access token associated with the bungie account.
1184
1185        Returns
1186        -------
1187        `collections.Sequence[aiobungie.crates.Friend]`
1188            A sequence of the friends associated with that access token.
1189        """
1190
1191        resp = await self.rest.fetch_friends(access_token)
1192
1193        return self.factory.deserialize_friends(resp)

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> aiobungie.crates.friends.FriendRequestView:
1195    async def fetch_friend_requests(
1196        self, access_token: str, /
1197    ) -> friends.FriendRequestView:
1198        """Fetch pending bungie friend requests queue.
1199
1200        .. note::
1201            This requests OAuth2: ReadUserData scope.
1202
1203        Parameters
1204        -----------
1205        access_token : `str`
1206            The bearer access token associated with the bungie account.
1207
1208        Returns
1209        -------
1210        `aiobungie.crates.FriendRequestView`
1211            A friend requests view of that associated access token.
1212        """
1213
1214        resp = await self.rest.fetch_friend_requests(access_token)
1215
1216        return self.factory.deserialize_friend_requests(resp)

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_application(self, appid: int, /) -> aiobungie.crates.application.Application:
1220    async def fetch_application(self, appid: int, /) -> application.Application:
1221        """Fetch a Bungie application.
1222
1223        Parameters
1224        -----------
1225        appid: `int`
1226            The application id.
1227
1228        Returns
1229        --------
1230        `aiobungie.crates.Application`
1231            A Bungie application.
1232        """
1233        resp = await self.rest.fetch_application(appid)
1234
1235        return self.factory.deserialize_app(resp)

Fetch a Bungie application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_public_milestone_content( self, milestone_hash: int, /) -> aiobungie.crates.milestones.MilestoneContent:
1239    async def fetch_public_milestone_content(
1240        self, milestone_hash: int, /
1241    ) -> milestones.MilestoneContent:
1242        """Fetch the milestone content given its hash.
1243
1244        Parameters
1245        ----------
1246        milestone_hash : `int`
1247            The milestone hash.
1248
1249        Returns
1250        -------
1251        `aiobungie.crates.milestones.MilestoneContent`
1252            A milestone content object.
1253        """
1254        ...
1255        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1256        return self.factory.deserialize_public_milestone_content(resp)

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
  • aiobungie.crates.milestones.MilestoneContent: A milestone content object.
@typing.final
class ClosedReasons(aiobungie.Flag):
771@typing.final
772class ClosedReasons(Flag):
773    """A Flags enumeration representing the reasons why a person can't join this user's fireteam."""
774
775    NONE = 0
776    MATCHMAKING = 1 << 0
777    LOADING = 1 << 1
778    SOLO = 1 << 2
779    """The activity is required to be played solo."""
780    INTERNAL_REASONS = 1 << 3
781    """
782    The user can't be joined for one of a variety of internal reasons.
783    Basically, the game can't let you join at this time,
784    but for reasons that aren't under the control of this user
785    """
786    DISALLOWED_BY_GAME_STATE = 1 << 4
787    """The user's current activity/quest/other transitory game state is preventing joining."""
788    OFFLINE = 32768
789    """The user appears offline."""

A Flags enumeration representing the reasons why a person can't join this user's fireteam.

NONE = <ClosedReasons.NONE: 0>
MATCHMAKING = <ClosedReasons.MATCHMAKING: 1>
LOADING = <ClosedReasons.LOADING: 2>
SOLO = <ClosedReasons.SOLO: 4>

The activity is required to be played solo.

INTERNAL_REASONS = <ClosedReasons.INTERNAL_REASONS: 8>

The user can't be joined for one of a variety of internal reasons. Basically, the game can't let you join at this time, but for reasons that aren't under the control of this user

DISALLOWED_BY_GAME_STATE = <ClosedReasons.DISALLOWED_BY_GAME_STATE: 16>

The user's current activity/quest/other transitory game state is preventing joining.

OFFLINE = <ClosedReasons.OFFLINE: 32768>

The user appears offline.

Inherited Members
Flag
name
value
@typing.final
class ComponentFields(aiobungie.Enum):
74@typing.final
75class ComponentFields(enums.Enum):
76    """An enum that provides fields found in a base component response."""
77
78    PRIVACY = ComponentPrivacy.NONE
79    DISABLED = False

An enum that provides fields found in a base component response.

PRIVACY = <ComponentFields.PRIVACY: NONE>
DISABLED = <ComponentFields.PRIVACY: NONE>
Inherited Members
Enum
name
value
@typing.final
class ComponentPrivacy(builtins.int, aiobungie.Enum):
65@typing.final
66class ComponentPrivacy(int, enums.Enum):
67    """An enum the provides privacy settings for profile components."""
68
69    NONE = 0
70    PUBLIC = 1
71    PRIVATE = 2

An enum the provides privacy settings for profile components.

NONE = <ComponentPrivacy.NONE: 0>
PUBLIC = <ComponentPrivacy.PUBLIC: 1>
PRIVATE = <ComponentPrivacy.PRIVATE: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class ComponentType(aiobungie.Enum):
347@typing.final
348class ComponentType(Enum):
349    """An Enum for Destiny 2 profile Components."""
350
351    NONE = 0
352
353    PROFILE = 100
354    PROFILE_INVENTORIES = 102
355    PROFILE_CURRENCIES = 103
356    PROFILE_PROGRESSION = 104
357    ALL_PROFILES = (
358        PROFILE,
359        PROFILE_INVENTORIES,
360        PROFILE_CURRENCIES,
361        PROFILE_PROGRESSION,
362    )
363    """All profile components."""
364
365    VENDORS = 400
366    VENDOR_SALES = 402
367    VENDOR_RECEIPTS = 101
368    ALL_VENDORS = (VENDORS, VENDOR_RECEIPTS, VENDOR_SALES)
369    """All vendor components."""
370
371    # Items
372    ITEM_INSTANCES = 300
373    ITEM_OBJECTIVES = 301
374    ITEM_PERKS = 302
375    ITEM_RENDER_DATA = 303
376    ITEM_STATS = 304
377    ITEM_SOCKETS = 305
378    ITEM_TALENT_GRINDS = 306
379    ITEM_PLUG_STATES = 308
380    ITEM_PLUG_OBJECTIVES = 309
381    ITEM_REUSABLE_PLUGS = 310
382
383    ALL_ITEMS = (
384        ITEM_PLUG_OBJECTIVES,
385        ITEM_PLUG_STATES,
386        ITEM_SOCKETS,
387        ITEM_INSTANCES,
388        ITEM_OBJECTIVES,
389        ITEM_PERKS,
390        ITEM_RENDER_DATA,
391        ITEM_STATS,
392        ITEM_TALENT_GRINDS,
393        ITEM_REUSABLE_PLUGS,
394    )
395    """All item components."""
396
397    PLATFORM_SILVER = 105
398    KIOSKS = 500
399    CURRENCY_LOOKUPS = 600
400    PRESENTATION_NODES = 700
401    COLLECTIBLES = 800
402    RECORDS = 900
403    TRANSITORY = 1000
404    METRICS = 1100
405    INVENTORIES = 102
406    STRING_VARIABLES = 1200
407    CRAFTABLES = 1300
408
409    CHARACTERS = 200
410    CHARACTER_INVENTORY = 201
411    CHARECTER_PROGRESSION = 202
412    CHARACTER_RENDER_DATA = 203
413    CHARACTER_ACTIVITIES = 204
414    CHARACTER_EQUIPMENT = 205
415    CHARACTER_LOADOUTS = 206
416
417    ALL_CHARACTERS = (
418        CHARACTERS,
419        CHARACTER_INVENTORY,
420        CHARECTER_PROGRESSION,
421        CHARACTER_RENDER_DATA,
422        CHARACTER_ACTIVITIES,
423        CHARACTER_EQUIPMENT,
424        CHARACTER_LOADOUTS,
425        RECORDS,
426    )
427    """All character components."""
428
429    # Ignores: We those are iterables, They're tuples.
430    ALL = (
431        *ALL_PROFILES,  # pyright: ignore[reportGeneralTypeIssues]
432        *ALL_CHARACTERS,  # pyright: ignore[reportGeneralTypeIssues]
433        *ALL_VENDORS,  # pyright: ignore[reportGeneralTypeIssues]
434        *ALL_ITEMS,  # pyright: ignore[reportGeneralTypeIssues]
435        RECORDS,
436        CURRENCY_LOOKUPS,
437        PRESENTATION_NODES,
438        COLLECTIBLES,
439        KIOSKS,
440        METRICS,
441        PLATFORM_SILVER,
442        INVENTORIES,
443        STRING_VARIABLES,
444        TRANSITORY,
445        CRAFTABLES,
446    )
447    """ALl components included."""

An Enum for Destiny 2 profile Components.

NONE = <ComponentType.NONE: 0>
PROFILE = <ComponentType.PROFILE: 100>
PROFILE_INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
PROFILE_CURRENCIES = <ComponentType.PROFILE_CURRENCIES: 103>
PROFILE_PROGRESSION = <ComponentType.PROFILE_PROGRESSION: 104>
ALL_PROFILES = <ComponentType.ALL_PROFILES: (100, 102, 103, 104)>

All profile components.

VENDORS = <ComponentType.VENDORS: 400>
VENDOR_SALES = <ComponentType.VENDOR_SALES: 402>
VENDOR_RECEIPTS = <ComponentType.VENDOR_RECEIPTS: 101>
ALL_VENDORS = <ComponentType.ALL_VENDORS: (400, 101, 402)>

All vendor components.

ITEM_INSTANCES = <ComponentType.ITEM_INSTANCES: 300>
ITEM_OBJECTIVES = <ComponentType.ITEM_OBJECTIVES: 301>
ITEM_PERKS = <ComponentType.ITEM_PERKS: 302>
ITEM_RENDER_DATA = <ComponentType.ITEM_RENDER_DATA: 303>
ITEM_STATS = <ComponentType.ITEM_STATS: 304>
ITEM_SOCKETS = <ComponentType.ITEM_SOCKETS: 305>
ITEM_TALENT_GRINDS = <ComponentType.ITEM_TALENT_GRINDS: 306>
ITEM_PLUG_STATES = <ComponentType.ITEM_PLUG_STATES: 308>
ITEM_PLUG_OBJECTIVES = <ComponentType.ITEM_PLUG_OBJECTIVES: 309>
ITEM_REUSABLE_PLUGS = <ComponentType.ITEM_REUSABLE_PLUGS: 310>
ALL_ITEMS = <ComponentType.ALL_ITEMS: (309, 308, 305, 300, 301, 302, 303, 304, 306, 310)>

All item components.

PLATFORM_SILVER = <ComponentType.PLATFORM_SILVER: 105>
KIOSKS = <ComponentType.KIOSKS: 500>
CURRENCY_LOOKUPS = <ComponentType.CURRENCY_LOOKUPS: 600>
PRESENTATION_NODES = <ComponentType.PRESENTATION_NODES: 700>
COLLECTIBLES = <ComponentType.COLLECTIBLES: 800>
RECORDS = <ComponentType.RECORDS: 900>
TRANSITORY = <ComponentType.TRANSITORY: 1000>
METRICS = <ComponentType.METRICS: 1100>
INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
STRING_VARIABLES = <ComponentType.STRING_VARIABLES: 1200>
CRAFTABLES = <ComponentType.CRAFTABLES: 1300>
CHARACTERS = <ComponentType.CHARACTERS: 200>
CHARACTER_INVENTORY = <ComponentType.CHARACTER_INVENTORY: 201>
CHARECTER_PROGRESSION = <ComponentType.CHARECTER_PROGRESSION: 202>
CHARACTER_RENDER_DATA = <ComponentType.CHARACTER_RENDER_DATA: 203>
CHARACTER_ACTIVITIES = <ComponentType.CHARACTER_ACTIVITIES: 204>
CHARACTER_EQUIPMENT = <ComponentType.CHARACTER_EQUIPMENT: 205>
CHARACTER_LOADOUTS = <ComponentType.CHARACTER_LOADOUTS: 206>
ALL_CHARACTERS = <ComponentType.ALL_CHARACTERS: (200, 201, 202, 203, 204, 205, 206, 900)>

All character components.

ALL = <ComponentType.ALL: (100, 102, 103, 104, 200, 201, 202, 203, 204, 205, 206, 900, 400, 101, 402, 309, 308, 305, 300, 301, 302, 303, 304, 306, 310, 900, 600, 700, 800, 500, 1100, 105, 102, 1200, 1000, 1300)>

ALl components included.

Inherited Members
Enum
name
value
@typing.final
class CredentialType(builtins.int, aiobungie.Enum):
653@typing.final
654class CredentialType(int, Enum):
655    """The types of the accounts system supports at bungie."""
656
657    NONE = 0
658    XUID = 1
659    PSNID = 2
660    WILD = 3
661    FAKE = 4
662    FACEBOOK = 5
663    GOOGLE = 8
664    WINDOWS = 9
665    DEMONID = 10
666    STEAMID = 12
667    BATTLENETID = 14
668    STADIAID = 16
669    TWITCHID = 18

The types of the accounts system supports at bungie.

NONE = <CredentialType.NONE: 0>
XUID = <CredentialType.XUID: 1>
PSNID = <CredentialType.PSNID: 2>
WILD = <CredentialType.WILD: 3>
FAKE = <CredentialType.FAKE: 4>
FACEBOOK = <CredentialType.FACEBOOK: 5>
GOOGLE = <CredentialType.GOOGLE: 8>
WINDOWS = <CredentialType.WINDOWS: 9>
DEMONID = <CredentialType.DEMONID: 10>
STEAMID = <CredentialType.STEAMID: 12>
BATTLENETID = <CredentialType.BATTLENETID: 14>
STADIAID = <CredentialType.STADIAID: 16>
TWITCHID = <CredentialType.TWITCHID: 18>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class DamageType(builtins.int, aiobungie.Enum):
531@typing.final
532class DamageType(int, Enum):
533    """Enums for Destiny Damage types"""
534
535    NONE = 0
536    KINETIC = 1
537    ARC = 2
538    SOLAR = 3
539    VOID = 4
540    RAID = 5
541    """This is a special damage type reserved for some raid activity encounters."""
542    STASIS = 6

Enums for Destiny Damage types

NONE = <DamageType.NONE: 0>
KINETIC = <DamageType.KINETIC: 1>
ARC = <DamageType.ARC: 2>
SOLAR = <DamageType.SOLAR: 3>
VOID = <DamageType.VOID: 4>
RAID = <DamageType.RAID: 5>

This is a special damage type reserved for some raid activity encounters.

STASIS = <DamageType.STASIS: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Difficulty(builtins.int, aiobungie.Enum):
63@typing.final
64class Difficulty(int, enums.Enum):
65    """An enum for activities difficulties."""
66
67    TRIVIAL = 0
68    EASY = 1
69    NORMAL = 2
70    CHALLENGING = 3
71    HARD = 4
72    BRAVE = 5
73    ALMOST_IMPOSSIBLE = 6
74    IMPOSSIBLE = 7

An enum for activities difficulties.

TRIVIAL = <Difficulty.TRIVIAL: 0>
EASY = <Difficulty.EASY: 1>
NORMAL = <Difficulty.NORMAL: 2>
CHALLENGING = <Difficulty.CHALLENGING: 3>
HARD = <Difficulty.HARD: 4>
BRAVE = <Difficulty.BRAVE: 5>
ALMOST_IMPOSSIBLE = <Difficulty.ALMOST_IMPOSSIBLE: 6>
IMPOSSIBLE = <Difficulty.IMPOSSIBLE: 7>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Dungeon(builtins.int, aiobungie.Enum):
149@typing.final
150class Dungeon(int, Enum):
151    """An Enum for all available Dungeon/Like missions in Destiny 2."""
152
153    NORMAL_PRESAGE = 2124066889
154    """Normal Presage"""
155
156    MASTER_PRESAGE = 4212753278
157    """Master Presage"""
158
159    HARBINGER = 1738383283
160    """Harbinger"""
161
162    PROPHECY = 4148187374
163    """Prophecy"""
164
165    MASTER_POH = 785700673
166    """Master Pit of Heresy?"""
167
168    LEGEND_POH = 785700678
169    """Legend Pit of Heresy?"""
170
171    POH = 1375089621
172    """Normal Pit of Heresy."""
173
174    SHATTERED = 2032534090
175    """Shattered Throne"""
176
177    GOA_LEGEND = 4078656646
178    """Grasp of Avarice legend."""
179
180    GOA_MASTER = 3774021532
181    """Grasp of Avarice master."""

An Enum for all available Dungeon/Like missions in Destiny 2.

NORMAL_PRESAGE = <Dungeon.NORMAL_PRESAGE: 2124066889>

Normal Presage

MASTER_PRESAGE = <Dungeon.MASTER_PRESAGE: 4212753278>

Master Presage

HARBINGER = <Dungeon.HARBINGER: 1738383283>

Harbinger

PROPHECY = <Dungeon.PROPHECY: 4148187374>

Prophecy

MASTER_POH = <Dungeon.MASTER_POH: 785700673>

Master Pit of Heresy?

LEGEND_POH = <Dungeon.LEGEND_POH: 785700678>

Legend Pit of Heresy?

POH = <Dungeon.POH: 1375089621>

Normal Pit of Heresy.

SHATTERED = <Dungeon.SHATTERED: 2032534090>

Shattered Throne

GOA_LEGEND = <Dungeon.GOA_LEGEND: 4078656646>

Grasp of Avarice legend.

GOA_MASTER = <Dungeon.GOA_MASTER: 3774021532>

Grasp of Avarice master.

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
class EmptyFactory(aiobungie.Factory):
2420class EmptyFactory(Factory):
2421    """A stand-alone factory that doesn't require a client instance.
2422
2423    # Example
2424    ---------
2425    ```py
2426    # We'll implement a serializable RESTClient.
2427    @dataclass(slots=True)
2428    class MyClient(aiobungie.traits.Serializable):
2429        rest = aiobungie.RESTClient(env["CLIENT_TOKEN"])
2430        my_name = "Fate怒"
2431        my_code = 4275
2432
2433        # Must implement this one method.
2434        @property
2435        def factory(self) -> aiobungie.EmptyFactory:
2436            # Return an empty factory
2437            return aiobungie.EmptyFactory()
2438
2439        async def my_memberships(self) -> Sequence[aiobungie.crates.DestinyMembership]:
2440            # Note, Do not call methods within objects, Since this is an empty
2441            # factory, The client reference that makes these calls will be `None`.
2442            response = await self.rest.fetch_membership(self.my_name, self.my_code)
2443            return self.factory.deserialize_destiny_memberships(response)
2444
2445
2446        async def main() -> None:
2447            client = MyClient()
2448            async with client.client:
2449                print(await client.my_memberships())
2450
2451    asyncio.run(main())
2452    ```
2453    """
2454
2455    __slots__ = ()
2456
2457    if typing.TYPE_CHECKING:
2458        # We explicitly want this to be `None`.
2459        _net: None
2460
2461    def __init__(self, net: None = None) -> None:
2462        self._net = net

A stand-alone factory that doesn't require a client instance.

# Example

# We'll implement a serializable RESTClient.
@dataclass(slots=True)
class MyClient(aiobungie.traits.Serializable):
    rest = aiobungie.RESTClient(env["CLIENT_TOKEN"])
    my_name = "Fate怒"
    my_code = 4275

    # Must implement this one method.
    @property
    def factory(self) -> aiobungie.EmptyFactory:
        # Return an empty factory
        return aiobungie.EmptyFactory()

    async def my_memberships(self) -> Sequence[aiobungie.crates.DestinyMembership]:
        # Note, Do not call methods within objects, Since this is an empty
        # factory, The client reference that makes these calls will be `None`.
        response = await self.rest.fetch_membership(self.my_name, self.my_code)
        return self.factory.deserialize_destiny_memberships(response)


    async def main() -> None:
        client = MyClient()
        async with client.client:
            print(await client.my_memberships())

asyncio.run(main())
EmptyFactory(net: None = None)
2461    def __init__(self, net: None = None) -> None:
2462        self._net = net
Inherited Members
Factory
deserialize_bungie_user
deserialize_partial_bungie_user
deserialize_destiny_membership
deserialize_destiny_memberships
deserialize_user
deserialize_searched_user
deserialize_user_credentials
deserialize_user_themes
deserialize_clan
deserialize_clan_member
deserialize_clan_members
deserialize_group_member
deserialize_clan_conversations
deserialize_app_owner
deserialize_app
deserialize_profile
deserialize_profile_item
deserialize_objectives
deserialize_records
deserialize_character_records
deserialize_character_dye
deserialize_character_customization
deserialize_character_minimal_equipments
deserialize_character_render_data
deserialize_available_activity
deserialize_character_activity
deserialize_profile_items
deserialize_progressions
deserialize_milestone
deserialize_characters
deserialize_character
deserialize_character_equipments
deserialize_character_activities
deserialize_characters_render_data
deserialize_character_progressions
deserialize_character_progressions_mapping
deserialize_characters_records
deserialize_profile_records
deserialize_craftables_component
deserialize_components
deserialize_items_component
deserialize_character_component
deserialize_inventory_results
deserialize_inventory_entity
deserialize_objective_entity
deserialize_activity
deserialize_activities
deserialize_extended_weapon_values
deserialize_post_activity_player
deserialize_post_activity
deserialize_aggregated_activity
deserialize_aggregated_activities
deserialize_linked_profiles
deserialize_clan_banners
deserialize_public_milestone_content
deserialize_friend
deserialize_friends
deserialize_friend_requests
deserialize_fireteams
deserialize_fireteam_destiny_users
deserialize_fireteam_members
deserialize_available_fireteam
deserialize_available_fireteams
deserialize_fireteam_party
deserialize_seasonal_artifact
deserialize_profile_progression
deserialize_instanced_item
deserialize_item_energy
deserialize_item_perk
deserialize_item_socket
deserialize_item_stats_view
deserialize_plug_item_state
class Enum(enum.Enum):
69class Enum(__enum.Enum):
70    """Builtin Python enum with extra handlings."""
71
72    @property
73    def name(self) -> str:
74        return self._name_
75
76    @property
77    def value(self) -> typing.Any:
78        return self._value_
79
80    def __str__(self) -> str:
81        return self._name_
82
83    def __repr__(self) -> str:
84        return f"<{type(self).__name__}.{self._name_}: {self._value_!s}>"
85
86    def __int__(self) -> int:
87        return int(self.value)

Builtin Python enum with extra handlings.

name: str
72    @property
73    def name(self) -> str:
74        return self._name_

The name of the Enum member.

value: Any
76    @property
77    def value(self) -> typing.Any:
78        return self._value_

The value of the Enum member.

class Factory(aiobungie.interfaces.factory.FactoryInterface):
  60class Factory(interfaces.FactoryInterface):
  61    """The base deserialization factory class for all aiobungie objects.
  62
  63    This entity factory is used to deserialize JSON responses from the REST client and turning them
  64    into a `aiobungie.crates` Python classes.
  65    """
  66
  67    __slots__ = ("_net",)
  68
  69    def __init__(self, net: traits.Netrunner) -> None:
  70        self._net = net
  71
  72    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
  73        return user.BungieUser(
  74            id=int(data["membershipId"]),
  75            created_at=time.clean_date(data["firstAccess"]),
  76            name=data.get("cachedBungieGlobalDisplayName"),
  77            is_deleted=data["isDeleted"],
  78            about=data["about"],
  79            updated_at=time.clean_date(data["lastUpdate"]),
  80            psn_name=data.get("psnDisplayName", None),
  81            stadia_name=data.get("stadiaDisplayName", None),
  82            steam_name=data.get("steamDisplayName", None),
  83            twitch_name=data.get("twitchDisplayName", None),
  84            blizzard_name=data.get("blizzardDisplayName", None),
  85            status=data["statusText"],
  86            locale=data["locale"],
  87            picture=assets.Image(path=data["profilePicturePath"]),
  88            code=data.get("cachedBungieGlobalDisplayNameCode", None),
  89            unique_name=data.get("uniqueName", None),
  90            theme_id=int(data["profileTheme"]),
  91            show_activity=bool(data["showActivity"]),
  92            theme_name=data["profileThemeName"],
  93            display_title=data["userTitleDisplay"],
  94        )
  95
  96    def deserialize_partial_bungie_user(
  97        self, payload: typedefs.JSONObject
  98    ) -> user.PartialBungieUser:
  99        return user.PartialBungieUser(
 100            net=self._net,
 101            types=tuple(
 102                enums.MembershipType(type_)
 103                for type_ in payload.get("applicableMembershipTypes", ())
 104            ),
 105            name=payload.get("displayName"),
 106            id=int(payload["membershipId"]),
 107            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 108            is_public=payload["isPublic"],
 109            icon=assets.Image(path=payload.get("iconPath", "")),
 110            type=enums.MembershipType(payload["membershipType"]),
 111        )
 112
 113    def deserialize_destiny_membership(
 114        self, payload: typedefs.JSONObject
 115    ) -> user.DestinyMembership:
 116        name: str | None = None
 117        if (raw_name := payload.get("bungieGlobalDisplayName")) is not None:
 118            name = typedefs.unknown(raw_name)
 119
 120        return user.DestinyMembership(
 121            net=self._net,
 122            id=int(payload["membershipId"]),
 123            name=name,
 124            code=payload.get("bungieGlobalDisplayNameCode", None),
 125            last_seen_name=payload.get("LastSeenDisplayName")
 126            or payload.get("displayName")  # noqa: W503
 127            or "",  # noqa: W503
 128            type=enums.MembershipType(payload["membershipType"]),
 129            is_public=payload["isPublic"],
 130            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 131            icon=assets.Image(path=payload.get("iconPath", "")),
 132            types=tuple(
 133                enums.MembershipType(type_)
 134                for type_ in payload.get("applicableMembershipTypes", ())
 135            ),
 136        )
 137
 138    def deserialize_destiny_memberships(
 139        self, data: typedefs.JSONArray
 140    ) -> collections.Sequence[user.DestinyMembership]:
 141        return tuple(
 142            self.deserialize_destiny_membership(membership) for membership in data
 143        )
 144
 145    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
 146        primary_membership_id: int | None = None
 147        if raw_primary_id := data.get("primaryMembershipId"):
 148            primary_membership_id = int(raw_primary_id)
 149
 150        return user.User(
 151            bungie_user=self.deserialize_bungie_user(data["bungieNetUser"]),
 152            memberships=self.deserialize_destiny_memberships(
 153                data["destinyMemberships"]
 154            ),
 155            primary_membership_id=primary_membership_id,
 156        )
 157
 158    def deserialize_searched_user(
 159        self, payload: typedefs.JSONObject
 160    ) -> user.SearchableDestinyUser:
 161        code: int | None = None
 162        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
 163            code = int(raw_code)
 164
 165        bungie_id: int | None = None
 166        if raw_bungie_id := payload.get("bungieNetMembershipId"):
 167            bungie_id = int(raw_bungie_id)
 168
 169        return user.SearchableDestinyUser(
 170            name=typedefs.unknown(payload["bungieGlobalDisplayName"]),
 171            code=code,
 172            bungie_id=bungie_id,
 173            memberships=self.deserialize_destiny_memberships(
 174                payload["destinyMemberships"]
 175            ),
 176        )
 177
 178    def deserialize_user_credentials(
 179        self, payload: typedefs.JSONArray
 180    ) -> collections.Sequence[user.UserCredentials]:
 181        return tuple(
 182            user.UserCredentials(
 183                type=enums.CredentialType(int(creds["credentialType"])),
 184                display_name=creds["credentialDisplayName"],
 185                is_public=creds["isPublic"],
 186                self_as_string=creds.get("credentialAsString"),
 187            )
 188            for creds in payload
 189        )
 190
 191    def deserialize_user_themes(
 192        self, payload: typedefs.JSONArray
 193    ) -> collections.Sequence[user.UserThemes]:
 194        return tuple(
 195            user.UserThemes(
 196                id=int(entry["userThemeId"]),
 197                name=entry["userThemeName"] if "userThemeName" in entry else None,
 198                description=entry["userThemeDescription"]
 199                if "userThemeDescription" in entry
 200                else None,
 201            )
 202            for entry in payload
 203        )
 204
 205    def _deserialize_group_details(
 206        self,
 207        data: typedefs.JSONObject,
 208        current_user_memberships: collections.Mapping[str, clans.ClanMember]
 209        | None = None,
 210        clan_founder: clans.ClanMember | None = None,
 211    ) -> clans.Clan:
 212        features = data["features"]
 213        features_obj = clans.ClanFeatures(
 214            max_members=features["maximumMembers"],
 215            max_membership_types=features["maximumMembershipsOfGroupType"],
 216            capabilities=features["capabilities"],
 217            membership_types=features["membershipTypes"],
 218            invite_permissions=features["invitePermissionOverride"],
 219            update_banner_permissions=features["updateBannerPermissionOverride"],
 220            update_culture_permissions=features["updateCulturePermissionOverride"],
 221            join_level=features["joinLevel"],
 222        )
 223        information: typedefs.JSONObject = data["clanInfo"]
 224        progression: collections.Mapping[int, progressions.Progression] = {
 225            int(prog_hash): self.deserialize_progressions(prog)
 226            for prog_hash, prog in information["d2ClanProgressions"].items()
 227        }
 228
 229        return clans.Clan(
 230            net=self._net,
 231            id=int(data["groupId"]),
 232            name=data["name"],
 233            type=enums.GroupType(data["groupType"]),
 234            created_at=time.clean_date(data["creationDate"]),
 235            member_count=data["memberCount"],
 236            motto=data["motto"],
 237            about=data["about"],
 238            is_public=data["isPublic"],
 239            banner=assets.Image(path=data["bannerPath"]),
 240            avatar=assets.Image(path=data["avatarPath"]),
 241            tags=tuple(data["tags"]),
 242            features=features_obj,
 243            owner=clan_founder,
 244            progressions=progression,
 245            call_sign=information["clanCallsign"],
 246            banner_data=information["clanBannerData"],
 247            chat_security=data["chatSecurity"],
 248            conversation_id=int(data["conversationId"]),
 249            allow_chat=data["allowChat"],
 250            theme=data["theme"],
 251            current_user_membership=current_user_memberships,
 252        )
 253
 254    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
 255        current_user_map: collections.Mapping[str, clans.ClanMember] | None = None
 256        if raw_current_user := payload.get("currentUserMemberMap"):
 257            # This will get populated if only it was a GroupsV2.GroupResponse.
 258            # GroupsV2.GetGroupsForMemberResponse doesn't have this field.
 259            current_user_map = {
 260                membership_type: self.deserialize_clan_member(membership)
 261                for membership_type, membership in raw_current_user.items()
 262            }
 263
 264        return self._deserialize_group_details(
 265            data=payload["detail"],
 266            clan_founder=self.deserialize_clan_member(payload["founder"]),
 267            current_user_memberships=current_user_map,
 268        )
 269
 270    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
 271        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
 272        return clans.ClanMember(
 273            net=self._net,
 274            last_seen_name=destiny_user.last_seen_name,
 275            id=destiny_user.id,
 276            name=destiny_user.name,
 277            icon=destiny_user.icon,
 278            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
 279            group_id=int(data["groupId"]),
 280            joined_at=time.clean_date(data["joinDate"]),
 281            types=destiny_user.types,
 282            is_public=destiny_user.is_public,
 283            type=destiny_user.type,
 284            code=destiny_user.code,
 285            is_online=data["isOnline"],
 286            crossave_override=destiny_user.crossave_override,
 287            bungie_user=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
 288            if "bungieNetUserInfo" in data
 289            else None,
 290            member_type=enums.ClanMemberType(int(data["memberType"])),
 291        )
 292
 293    def deserialize_clan_members(
 294        self, data: typedefs.JSONObject, /
 295    ) -> iterators.Iterator[clans.ClanMember]:
 296        return iterators.Iterator(
 297            self.deserialize_clan_member(member) for member in data["results"]
 298        )
 299
 300    def deserialize_group_member(
 301        self, payload: typedefs.JSONObject
 302    ) -> clans.GroupMember:
 303        member = payload["member"]
 304        return clans.GroupMember(
 305            net=self._net,
 306            join_date=time.clean_date(member["joinDate"]),
 307            group_id=int(member["groupId"]),
 308            member_type=enums.ClanMemberType(member["memberType"]),
 309            is_online=member["isOnline"],
 310            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
 311            inactive_memberships=payload.get("areAllMembershipsInactive", None),
 312            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
 313            group=self._deserialize_group_details(payload["group"]),
 314        )
 315
 316    def _deserialize_clan_conversation(
 317        self, payload: typedefs.JSONObject
 318    ) -> clans.ClanConversation:
 319        return clans.ClanConversation(
 320            net=self._net,
 321            id=int(payload["conversationId"]),
 322            group_id=int(payload["groupId"]),
 323            name=typedefs.unknown(payload["chatName"]),
 324            chat_enabled=payload["chatEnabled"],
 325            security=payload["chatSecurity"],
 326        )
 327
 328    def deserialize_clan_conversations(
 329        self, payload: typedefs.JSONArray
 330    ) -> collections.Sequence[clans.ClanConversation]:
 331        return tuple(self._deserialize_clan_conversation(conv) for conv in payload)
 332
 333    def deserialize_app_owner(
 334        self, payload: typedefs.JSONObject
 335    ) -> application.ApplicationOwner:
 336        return application.ApplicationOwner(
 337            net=self._net,
 338            name=payload.get("bungieGlobalDisplayName"),
 339            id=int(payload["membershipId"]),
 340            type=enums.MembershipType(payload["membershipType"]),
 341            icon=assets.Image(path=payload["iconPath"]),
 342            is_public=payload["isPublic"],
 343            code=payload.get("bungieGlobalDisplayNameCode", None),
 344        )
 345
 346    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
 347        return application.Application(
 348            id=int(payload["applicationId"]),
 349            name=payload["name"],
 350            link=payload["link"],
 351            status=payload["status"],
 352            redirect_url=payload.get("redirectUrl", None),
 353            created_at=time.clean_date(payload["creationDate"]),
 354            published_at=time.clean_date(payload["firstPublished"]),
 355            owner=self.deserialize_app_owner(payload["team"][0]["user"]),
 356            scope=payload.get("scope"),
 357        )
 358
 359    def _set_character_attrs(self, payload: typedefs.JSONObject) -> character.Character:
 360        return character.Character(
 361            net=self._net,
 362            id=int(payload["characterId"]),
 363            gender=enums.Gender(payload["genderType"]),
 364            race=enums.Race(payload["raceType"]),
 365            class_type=enums.Class(payload["classType"]),
 366            emblem=assets.Image(path=payload["emblemBackgroundPath"])
 367            if "emblemBackgroundPath" in payload
 368            else None,
 369            emblem_icon=assets.Image(path=payload["emblemPath"])
 370            if "emblemPath" in payload
 371            else None,
 372            emblem_hash=int(payload["emblemHash"]) if "emblemHash" in payload else None,
 373            last_played=time.clean_date(payload["dateLastPlayed"]),
 374            total_played_time=int(payload["minutesPlayedTotal"]),
 375            member_id=int(payload["membershipId"]),
 376            member_type=enums.MembershipType(payload["membershipType"]),
 377            level=payload["baseCharacterLevel"],
 378            title_hash=payload.get("titleRecordHash", None),
 379            light=payload["light"],
 380            stats={enums.Stat(int(k)): v for k, v in payload["stats"].items()},
 381        )
 382
 383    def deserialize_profile(self, payload: typedefs.JSONObject, /) -> profile.Profile:
 384        payload = payload["data"]
 385        id = int(payload["userInfo"]["membershipId"])
 386        name = payload["userInfo"]["displayName"]
 387        is_public = payload["userInfo"]["isPublic"]
 388        type = enums.MembershipType(payload["userInfo"]["membershipType"])
 389        last_played = time.clean_date(payload["dateLastPlayed"])
 390        character_ids = tuple(int(cid) for cid in payload["characterIds"])
 391        power_cap = payload["currentSeasonRewardPowerCap"]
 392
 393        return profile.Profile(
 394            id=int(id),
 395            name=name,
 396            is_public=is_public,
 397            type=type,
 398            last_played=last_played,
 399            character_ids=character_ids,
 400            power_cap=power_cap,
 401            net=self._net,
 402        )
 403
 404    def deserialize_profile_item(
 405        self, payload: typedefs.JSONObject
 406    ) -> profile.ProfileItemImpl:
 407        instance_id: int | None = None
 408        if raw_instance_id := payload.get("itemInstanceId"):
 409            instance_id = int(raw_instance_id)
 410
 411        version_number: int | None = None
 412        if raw_version := payload.get("versionNumber"):
 413            version_number = int(raw_version)
 414
 415        transfer_status = enums.TransferStatus(payload["transferStatus"])
 416
 417        return profile.ProfileItemImpl(
 418            net=self._net,
 419            hash=payload["itemHash"],
 420            quantity=payload["quantity"],
 421            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
 422            location=enums.ItemLocation(payload["location"]),
 423            bucket=payload["bucketHash"],
 424            transfer_status=transfer_status,
 425            lockable=payload["lockable"],
 426            state=enums.ItemState(payload["state"]),
 427            dismantle_permissions=payload["dismantlePermission"],
 428            is_wrapper=payload["isWrapper"],
 429            instance_id=instance_id,
 430            version_number=version_number,
 431            ornament_id=payload.get("overrideStyleItemHash"),
 432        )
 433
 434    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
 435        return records.Objective(
 436            net=self._net,
 437            hash=payload["objectiveHash"],
 438            visible=payload["visible"],
 439            complete=payload["complete"],
 440            completion_value=payload["completionValue"],
 441            progress=payload.get("progress"),
 442            destination_hash=payload.get("destinationHash"),
 443            activity_hash=payload.get("activityHash"),
 444        )
 445
 446    # TODO: Remove **nodes and get it directly from the payload.
 447    def deserialize_records(
 448        self,
 449        payload: typedefs.JSONObject,
 450        scores: records.RecordScores | None = None,
 451        **nodes: int,
 452    ) -> records.Record:
 453        objectives: collections.Sequence[records.Objective] | None = None
 454        interval_objectives: collections.Sequence[records.Objective] | None = None
 455        record_state: records.RecordState | int
 456
 457        record_state = records.RecordState(payload["state"])
 458
 459        if raw_objs := payload.get("objectives"):
 460            objectives = tuple(self.deserialize_objectives(obj) for obj in raw_objs)
 461
 462        if raw_interval_objs := payload.get("intervalObjectives"):
 463            interval_objectives = tuple(
 464                self.deserialize_objectives(obj) for obj in raw_interval_objs
 465            )
 466
 467        return records.Record(
 468            scores=scores,
 469            categories_node_hash=nodes.get("categories_hash"),
 470            seals_node_hash=nodes.get("seals_hash"),
 471            state=record_state,
 472            objectives=objectives,
 473            interval_objectives=interval_objectives,
 474            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 475            completion_times=payload.get("completedCount", None),
 476            reward_visibility=payload.get("rewardVisibility"),
 477        )
 478
 479    def deserialize_character_records(
 480        self,
 481        payload: typedefs.JSONObject,
 482        scores: records.RecordScores | None = None,
 483        record_hashes: collections.Sequence[int] = (),
 484    ) -> records.CharacterRecord:
 485        record = self.deserialize_records(payload, scores)
 486        return records.CharacterRecord(
 487            scores=scores,
 488            categories_node_hash=record.categories_node_hash,
 489            seals_node_hash=record.seals_node_hash,
 490            state=record.state,
 491            objectives=record.objectives,
 492            interval_objectives=record.interval_objectives,
 493            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 494            completion_times=payload.get("completedCount"),
 495            reward_visibility=payload.get("rewardVisibility"),
 496            record_hashes=record_hashes,
 497        )
 498
 499    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
 500        return character.Dye(
 501            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
 502        )
 503
 504    def deserialize_character_customization(
 505        self, payload: typedefs.JSONObject
 506    ) -> character.CustomizationOptions:
 507        return character.CustomizationOptions(
 508            personality=payload["personality"],
 509            face=payload["face"],
 510            skin_color=payload["skinColor"],
 511            lip_color=payload["lipColor"],
 512            eye_color=payload["eyeColor"],
 513            hair_colors=payload.get("hairColors", ()),
 514            feature_colors=payload.get("featureColors", ()),
 515            decal_color=payload["decalColor"],
 516            wear_helmet=payload["wearHelmet"],
 517            hair_index=payload["hairIndex"],
 518            feature_index=payload["featureIndex"],
 519            decal_index=payload["decalIndex"],
 520        )
 521
 522    def deserialize_character_minimal_equipments(
 523        self, payload: typedefs.JSONObject
 524    ) -> character.MinimalEquipments:
 525        if raw_dyes := payload.get("dyes"):
 526            dyes = tuple(self.deserialize_character_dye(dye) for dye in raw_dyes)
 527        else:
 528            dyes = ()
 529
 530        return character.MinimalEquipments(
 531            net=self._net, item_hash=payload["itemHash"], dyes=dyes
 532        )
 533
 534    def deserialize_character_render_data(
 535        self, payload: typedefs.JSONObject, /
 536    ) -> character.RenderedData:
 537        return character.RenderedData(
 538            net=self._net,
 539            customization=self.deserialize_character_customization(
 540                payload["customization"]
 541            ),
 542            custom_dyes=tuple(
 543                self.deserialize_character_dye(dye)
 544                for dye in payload["customDyes"]
 545                if dye
 546            ),
 547            equipment=tuple(
 548                self.deserialize_character_minimal_equipments(equipment)
 549                for equipment in payload["peerView"]["equipment"]
 550            ),
 551        )
 552
 553    def deserialize_available_activity(
 554        self, payload: typedefs.JSONObject
 555    ) -> activity.AvailableActivity:
 556        return activity.AvailableActivity(
 557            hash=payload["activityHash"],
 558            is_new=payload["isNew"],
 559            is_completed=payload["isCompleted"],
 560            is_visible=payload["isVisible"],
 561            display_level=payload.get("displayLevel"),
 562            recommended_light=payload.get("recommendedLight"),
 563            difficulty=activity.Difficulty(payload["difficultyTier"]),
 564            can_join=payload["canJoin"],
 565            can_lead=payload["canLead"],
 566        )
 567
 568    def deserialize_character_activity(
 569        self, payload: typedefs.JSONObject
 570    ) -> activity.CharacterActivity:
 571        current_mode: enums.GameMode | None = None
 572        if raw_current_mode := payload.get("currentActivityModeType"):
 573            current_mode = enums.GameMode(raw_current_mode)
 574
 575        if raw_current_modes := payload.get("currentActivityModeTypes"):
 576            current_mode_types = tuple(
 577                enums.GameMode(type_) for type_ in raw_current_modes
 578            )
 579        else:
 580            current_mode_types = ()
 581
 582        return activity.CharacterActivity(
 583            date_started=time.clean_date(payload["dateActivityStarted"]),
 584            current_hash=payload["currentActivityHash"],
 585            current_mode_hash=payload["currentActivityModeHash"],
 586            current_mode=current_mode,
 587            current_mode_hashes=payload.get("currentActivityModeHashes", ()),
 588            current_mode_types=current_mode_types,
 589            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
 590            last_story_hash=payload["lastCompletedStoryHash"],
 591            available_activities=tuple(
 592                self.deserialize_available_activity(activity_)
 593                for activity_ in payload["availableActivities"]
 594            ),
 595        )
 596
 597    def deserialize_profile_items(
 598        self, payload: typedefs.JSONObject, /
 599    ) -> collections.Sequence[profile.ProfileItemImpl]:
 600        return tuple(self.deserialize_profile_item(item) for item in payload["items"])
 601
 602    def _deserialize_node(self, payload: typedefs.JSONObject) -> records.Node:
 603        return records.Node(
 604            state=int(payload["state"]),
 605            objective=self.deserialize_objectives(payload["objective"])
 606            if "objective" in payload
 607            else None,
 608            progress_value=int(payload["progressValue"]),
 609            completion_value=int(payload["completionValue"]),
 610            record_category_score=int(payload["recordCategoryScore"])
 611            if "recordCategoryScore" in payload
 612            else None,
 613        )
 614
 615    @staticmethod
 616    def _deserialize_collectible(payload: typedefs.JSONObject) -> items.Collectible:
 617        recent_collectibles: collections.Collection[int] | None = None
 618        if raw_recent_collectibles := payload.get("recentCollectibleHashes"):
 619            recent_collectibles = tuple(
 620                int(item_hash) for item_hash in raw_recent_collectibles
 621            )
 622
 623        collectibles: dict[int, int] = {}
 624        for item_hash, mapping in payload["collectibles"].items():
 625            collectibles[int(item_hash)] = int(mapping["state"])
 626
 627        return items.Collectible(
 628            recent_collectibles=recent_collectibles,
 629            collectibles=collectibles,
 630            collection_category_hash=int(payload["collectionCategoriesRootNodeHash"]),
 631            collection_badges_hash=int(payload["collectionBadgesRootNodeHash"]),
 632        )
 633
 634    @staticmethod
 635    def _deserialize_currencies(
 636        payload: typedefs.JSONObject,
 637    ) -> collections.Sequence[items.Currency]:
 638        return tuple(
 639            items.Currency(hash=int(item_hash), amount=int(amount))
 640            for item_hash, amount in payload["itemQuantities"].items()
 641        )
 642
 643    def deserialize_progressions(
 644        self, payload: typedefs.JSONObject
 645    ) -> progressions.Progression:
 646        return progressions.Progression(
 647            hash=int(payload["progressionHash"]),
 648            level=int(payload["level"]),
 649            cap=int(payload["levelCap"]),
 650            daily_limit=int(payload["dailyLimit"]),
 651            weekly_limit=int(payload["weeklyLimit"]),
 652            current_progress=int(payload["currentProgress"]),
 653            daily_progress=int(payload["dailyProgress"]),
 654            needed=int(payload["progressToNextLevel"]),
 655            next_level=int(payload["nextLevelAt"]),
 656        )
 657
 658    def _deserialize_factions(
 659        self, payload: typedefs.JSONObject
 660    ) -> progressions.Factions:
 661        progs = self.deserialize_progressions(payload)
 662        return progressions.Factions(
 663            hash=progs.hash,
 664            level=progs.level,
 665            cap=progs.cap,
 666            daily_limit=progs.daily_limit,
 667            weekly_limit=progs.weekly_limit,
 668            current_progress=progs.current_progress,
 669            daily_progress=progs.daily_progress,
 670            needed=progs.needed,
 671            next_level=progs.next_level,
 672            faction_hash=payload["factionHash"],
 673            faction_vendor_hash=payload["factionVendorIndex"],
 674        )
 675
 676    def _deserialize_milestone_available_quest(
 677        self, payload: typedefs.JSONObject
 678    ) -> milestones.MilestoneQuest:
 679        return milestones.MilestoneQuest(
 680            item_hash=payload["questItemHash"],
 681            status=self._deserialize_milestone_quest_status(payload["status"]),
 682        )
 683
 684    def _deserialize_milestone_activity(
 685        self, payload: typedefs.JSONObject
 686    ) -> milestones.MilestoneActivity:
 687        phases: collections.Sequence[milestones.MilestoneActivityPhase] | None = None
 688        if raw_phases := payload.get("phases"):
 689            phases = tuple(
 690                milestones.MilestoneActivityPhase(
 691                    is_completed=obj["complete"], hash=obj["phaseHash"]
 692                )
 693                for obj in raw_phases
 694            )
 695
 696        return milestones.MilestoneActivity(
 697            hash=payload["activityHash"],
 698            challenges=tuple(
 699                self.deserialize_objectives(obj["objective"])
 700                for obj in payload["challenges"]
 701            ),
 702            modifier_hashes=payload.get("modifierHashes"),
 703            boolean_options=payload.get("booleanActivityOptions"),
 704            phases=phases,
 705        )
 706
 707    def _deserialize_milestone_quest_status(
 708        self, payload: typedefs.JSONObject
 709    ) -> milestones.QuestStatus:
 710        return milestones.QuestStatus(
 711            net=self._net,
 712            quest_hash=payload["questHash"],
 713            step_hash=payload["stepHash"],
 714            step_objectives=tuple(
 715                self.deserialize_objectives(objective)
 716                for objective in payload["stepObjectives"]
 717            ),
 718            is_tracked=payload["tracked"],
 719            is_completed=payload["completed"],
 720            started=payload["started"],
 721            item_instance_id=payload["itemInstanceId"],
 722            vendor_hash=payload.get("vendorHash"),
 723            is_redeemed=payload["redeemed"],
 724        )
 725
 726    def _deserialize_milestone_rewards(
 727        self, payload: typedefs.JSONObject
 728    ) -> milestones.MilestoneReward:
 729        return milestones.MilestoneReward(
 730            category_hash=payload["rewardCategoryHash"],
 731            entries=tuple(
 732                milestones.MilestoneRewardEntry(
 733                    entry_hash=entry["rewardEntryHash"],
 734                    is_earned=entry["earned"],
 735                    is_redeemed=entry["redeemed"],
 736                )
 737                for entry in payload["entries"]
 738            ),
 739        )
 740
 741    def deserialize_milestone(
 742        self, payload: typedefs.JSONObject
 743    ) -> milestones.Milestone:
 744        start_date: datetime.datetime | None = None
 745        if raw_start_date := payload.get("startDate"):
 746            start_date = time.clean_date(raw_start_date)
 747
 748        end_date: datetime.datetime | None = None
 749        if raw_end_date := payload.get("endDate"):
 750            end_date = time.clean_date(raw_end_date)
 751
 752        rewards: collections.Collection[milestones.MilestoneReward] | None = None
 753        if raw_rewards := payload.get("rewards"):
 754            rewards = tuple(
 755                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
 756            )
 757
 758        activities: collections.Sequence[milestones.MilestoneActivity] | None = None
 759        if raw_activities := payload.get("activities"):
 760            activities = tuple(
 761                self._deserialize_milestone_activity(active)
 762                for active in raw_activities
 763            )
 764
 765        quests: collections.Sequence[milestones.MilestoneQuest] | None = None
 766        if raw_quests := payload.get("availableQuests"):
 767            quests = tuple(
 768                self._deserialize_milestone_available_quest(quest)
 769                for quest in raw_quests
 770            )
 771
 772        vendors: collections.Sequence[milestones.MilestoneVendor] | None = None
 773        if raw_vendors := payload.get("vendors"):
 774            vendors = tuple(
 775                milestones.MilestoneVendor(
 776                    vendor_hash=vendor["vendorHash"],
 777                    preview_itemhash=vendor.get("previewItemHash"),
 778                )
 779                for vendor in raw_vendors
 780            )
 781
 782        return milestones.Milestone(
 783            hash=payload["milestoneHash"],
 784            start_date=start_date,
 785            end_date=end_date,
 786            order=payload["order"],
 787            rewards=rewards,
 788            available_quests=quests,
 789            activities=activities,
 790            vendors=vendors,
 791        )
 792
 793    def _deserialize_artifact_tiers(
 794        self, payload: typedefs.JSONObject
 795    ) -> season.ArtifactTier:
 796        return season.ArtifactTier(
 797            hash=payload["tierHash"],
 798            is_unlocked=payload["isUnlocked"],
 799            points_to_unlock=payload["pointsToUnlock"],
 800            items=tuple(
 801                season.ArtifactTierItem(
 802                    hash=item["itemHash"], is_active=item["isActive"]
 803                )
 804                for item in payload["items"]
 805            ),
 806        )
 807
 808    def deserialize_characters(
 809        self, payload: typedefs.JSONObject
 810    ) -> collections.Mapping[int, character.Character]:
 811        return {
 812            int(char_id): self._set_character_attrs(char)
 813            for char_id, char in payload["data"].items()
 814        }
 815
 816    def deserialize_character(
 817        self, payload: typedefs.JSONObject
 818    ) -> character.Character:
 819        return self._set_character_attrs(payload)
 820
 821    def deserialize_character_equipments(
 822        self, payload: typedefs.JSONObject
 823    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
 824        return {
 825            int(char_id): self.deserialize_profile_items(item)
 826            for char_id, item in payload["data"].items()
 827        }
 828
 829    def deserialize_character_activities(
 830        self, payload: typedefs.JSONObject
 831    ) -> collections.Mapping[int, activity.CharacterActivity]:
 832        return {
 833            int(char_id): self.deserialize_character_activity(data)
 834            for char_id, data in payload["data"].items()
 835        }
 836
 837    def deserialize_characters_render_data(
 838        self, payload: typedefs.JSONObject
 839    ) -> collections.Mapping[int, character.RenderedData]:
 840        return {
 841            int(char_id): self.deserialize_character_render_data(data)
 842            for char_id, data in payload["data"].items()
 843        }
 844
 845    def deserialize_character_progressions(
 846        self, payload: typedefs.JSONObject
 847    ) -> character.CharacterProgression:
 848        progressions_ = {
 849            int(prog_id): self.deserialize_progressions(prog)
 850            for prog_id, prog in payload["progressions"].items()
 851        }
 852
 853        factions = {
 854            int(faction_id): self._deserialize_factions(faction)
 855            for faction_id, faction in payload["factions"].items()
 856        }
 857
 858        milestones_ = {
 859            int(milestone_hash): self.deserialize_milestone(milestone)
 860            for milestone_hash, milestone in payload["milestones"].items()
 861        }
 862
 863        uninstanced_item_objectives = {
 864            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
 865            for item_hash, obj in payload["uninstancedItemObjectives"].items()
 866        }
 867
 868        artifact = payload["seasonalArtifact"]
 869        seasonal_artifact = season.CharacterScopedArtifact(
 870            hash=artifact["artifactHash"],
 871            points_used=artifact["pointsUsed"],
 872            reset_count=artifact["resetCount"],
 873            tiers=tuple(
 874                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
 875            ),
 876        )
 877        checklists = payload["checklists"]
 878
 879        return character.CharacterProgression(
 880            progressions=progressions_,
 881            factions=factions,
 882            checklists=checklists,
 883            milestones=milestones_,
 884            seasonal_artifact=seasonal_artifact,
 885            uninstanced_item_objectives=uninstanced_item_objectives,
 886        )
 887
 888    # fmt: off
 889    def deserialize_character_progressions_mapping(self, payload: typedefs.JSONObject) -> collections.Mapping[int, character.CharacterProgression]:
 890        character_progressions: collections.MutableMapping[int, character.CharacterProgression] = {}
 891        for char_id, data in payload["data"].items():
 892            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)
 893        return character_progressions
 894    # fmt: on
 895
 896    def deserialize_characters_records(
 897        self,
 898        payload: typedefs.JSONObject,
 899    ) -> collections.Mapping[int, records.CharacterRecord]:
 900        return {
 901            int(rec_id): self.deserialize_character_records(
 902                rec, record_hashes=payload.get("featuredRecordHashes", ())
 903            )
 904            for rec_id, rec in payload["records"].items()
 905        }
 906
 907    def deserialize_profile_records(
 908        self, payload: typedefs.JSONObject
 909    ) -> collections.Mapping[int, records.Record]:
 910        raw_profile_records = payload["data"]
 911        scores = records.RecordScores(
 912            current_score=raw_profile_records["score"],
 913            legacy_score=raw_profile_records["legacyScore"],
 914            lifetime_score=raw_profile_records["lifetimeScore"],
 915        )
 916        return {
 917            int(record_id): self.deserialize_records(
 918                record,
 919                scores,
 920                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
 921                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
 922            )
 923            for record_id, record in raw_profile_records["records"].items()
 924        }
 925
 926    def _deserialize_craftable_socket_plug(
 927        self, payload: typedefs.JSONObject
 928    ) -> items.CraftableSocketPlug:
 929        return items.CraftableSocketPlug(
 930            item_hash=int(payload["plugItemHash"]),
 931            failed_requirement_indexes=payload.get("failedRequirementIndexes", ()),
 932        )
 933
 934    def _deserialize_craftable_socket(
 935        self, payload: typedefs.JSONObject
 936    ) -> items.CraftableSocket:
 937        if raw_plug := payload.get("plug"):
 938            plugs = tuple(
 939                self._deserialize_craftable_socket_plug(plug) for plug in raw_plug
 940            )
 941        else:
 942            plugs = ()
 943
 944        return items.CraftableSocket(
 945            plug_set_hash=int(payload["plugSetHash"]), plugs=plugs
 946        )
 947
 948    def _deserialize_craftable_item(
 949        self, payload: typedefs.JSONObject
 950    ) -> items.CraftableItem:
 951        return items.CraftableItem(
 952            is_visible=payload["visible"],
 953            failed_requirement_indexes=payload.get("failedRequirementIndexes", ()),
 954            sockets=tuple(
 955                self._deserialize_craftable_socket(socket)
 956                for socket in payload["sockets"]
 957            ),
 958        )
 959
 960    def deserialize_craftables_component(
 961        self, payload: typedefs.JSONObject
 962    ) -> components.CraftablesComponent:
 963        return components.CraftablesComponent(
 964            net=self._net,
 965            craftables={
 966                int(item_id): self._deserialize_craftable_item(item)
 967                for item_id, item in payload["craftables"].items()
 968                if item is not None
 969            },
 970            crafting_root_node_hash=payload["craftingRootNodeHash"],
 971        )
 972
 973    def deserialize_components(  # noqa: C901 Too complex.
 974        self, payload: typedefs.JSONObject
 975    ) -> components.Component:
 976        # Due to how complex this method is, We'll stick to
 977        # typing.Optional here.
 978
 979        profile_: profile.Profile | None = None
 980        if raw_profile := payload.get("profile"):
 981            profile_ = self.deserialize_profile(raw_profile)
 982
 983        profile_progression: profile.ProfileProgression | None = None
 984        if raw_profile_progression := payload.get("profileProgression"):
 985            profile_progression = self.deserialize_profile_progression(
 986                raw_profile_progression
 987            )
 988
 989        profile_currencies: typing.Optional[
 990            collections.Sequence[profile.ProfileItemImpl]
 991        ] = None
 992        if raw_profile_currencies := payload.get("profileCurrencies"):
 993            if "data" in raw_profile_currencies:
 994                profile_currencies = self.deserialize_profile_items(
 995                    raw_profile_currencies["data"]
 996                )
 997
 998        profile_inventories: typing.Optional[
 999            collections.Sequence[profile.ProfileItemImpl]
1000        ] = None
1001        if raw_profile_inventories := payload.get("profileInventory"):
1002            if "data" in raw_profile_inventories:
1003                profile_inventories = self.deserialize_profile_items(
1004                    raw_profile_inventories["data"]
1005                )
1006
1007        profile_records: typing.Optional[collections.Mapping[int, records.Record]] = (
1008            None
1009        )
1010
1011        if raw_profile_records_ := payload.get("profileRecords"):
1012            profile_records = self.deserialize_profile_records(raw_profile_records_)
1013
1014        characters: typing.Optional[collections.Mapping[int, character.Character]] = (
1015            None
1016        )
1017        if raw_characters := payload.get("characters"):
1018            characters = self.deserialize_characters(raw_characters)
1019
1020        character_records: typing.Optional[
1021            collections.Mapping[int, records.CharacterRecord]
1022        ] = None
1023
1024        if raw_character_records := payload.get("characterRecords"):
1025            # Had to do it in two steps..
1026            to_update = {}
1027            for _, data in raw_character_records["data"].items():
1028                for record_id, record in data.items():
1029                    to_update[record_id] = record
1030
1031            character_records = {
1032                int(rec_id): self.deserialize_character_records(
1033                    rec, record_hashes=to_update.get("featuredRecordHashes", ())
1034                )
1035                for rec_id, rec in to_update["records"].items()
1036            }
1037
1038        character_equipments: typing.Optional[
1039            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1040        ] = None
1041        if raw_character_equips := payload.get("characterEquipment"):
1042            character_equipments = self.deserialize_character_equipments(
1043                raw_character_equips
1044            )
1045
1046        character_inventories: typing.Optional[
1047            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1048        ] = None
1049        if raw_character_inventories := payload.get("characterInventories"):
1050            if "data" in raw_character_inventories:
1051                character_inventories = self.deserialize_character_equipments(
1052                    raw_character_inventories
1053                )
1054
1055        character_activities: typing.Optional[
1056            collections.Mapping[int, activity.CharacterActivity]
1057        ] = None
1058        if raw_char_acts := payload.get("characterActivities"):
1059            character_activities = self.deserialize_character_activities(raw_char_acts)
1060
1061        character_render_data: typing.Optional[
1062            collections.Mapping[int, character.RenderedData]
1063        ] = None
1064        if raw_character_render_data := payload.get("characterRenderData"):
1065            character_render_data = self.deserialize_characters_render_data(
1066                raw_character_render_data
1067            )
1068
1069        character_progressions: typing.Optional[
1070            collections.Mapping[int, character.CharacterProgression]
1071        ] = None
1072
1073        if raw_character_progressions := payload.get("characterProgressions"):
1074            character_progressions = self.deserialize_character_progressions_mapping(
1075                raw_character_progressions
1076            )
1077
1078        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1079        if raw_profile_string_vars := payload.get("profileStringVariables"):
1080            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1081
1082        character_string_vars: typing.Optional[
1083            collections.Mapping[int, collections.Mapping[int, int]]
1084        ] = None
1085        if raw_character_string_vars := payload.get("characterStringVariables"):
1086            character_string_vars = {
1087                int(char_id): data["integerValuesByHash"]
1088                for char_id, data in raw_character_string_vars["data"].items()
1089            }
1090
1091        metrics: typing.Optional[
1092            collections.Sequence[
1093                collections.Mapping[int, tuple[bool, records.Objective | None]]
1094            ]
1095        ] = None
1096        root_node_hash: int | None = None
1097
1098        if raw_metrics := payload.get("metrics"):
1099            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1100            metrics = tuple(
1101                {
1102                    int(metrics_hash): (
1103                        data["invisible"],
1104                        self.deserialize_objectives(data["objectiveProgress"])
1105                        if "objectiveProgress" in data
1106                        else None,
1107                    )
1108                }
1109                for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1110            )
1111        transitory: fireteams.FireteamParty | None = None
1112        if raw_transitory := payload.get("profileTransitoryData"):
1113            if "data" in raw_transitory:
1114                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1115
1116        item_components: components.ItemsComponent | None = None
1117        if raw_item_components := payload.get("itemComponents"):
1118            item_components = self.deserialize_items_component(raw_item_components)
1119
1120        profile_plugsets: typing.Optional[
1121            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1122        ] = None
1123
1124        if raw_profile_plugs := payload.get("profilePlugSets"):
1125            profile_plugsets = {
1126                int(index): [self.deserialize_plug_item_state(state) for state in data]
1127                for index, data in raw_profile_plugs["data"]["plugs"].items()
1128            }
1129
1130        character_plugsets: typing.Optional[
1131            collections.Mapping[
1132                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1133            ]
1134        ] = None
1135        if raw_char_plugsets := payload.get("characterPlugSets"):
1136            character_plugsets = {
1137                int(char_id): {
1138                    int(index): [
1139                        self.deserialize_plug_item_state(state) for state in data
1140                    ]
1141                    for index, data in inner["plugs"].items()
1142                }
1143                for char_id, inner in raw_char_plugsets["data"].items()
1144            }
1145
1146        character_collectibles: typing.Optional[
1147            collections.Mapping[int, items.Collectible]
1148        ] = None
1149        if raw_character_collectibles := payload.get("characterCollectibles"):
1150            character_collectibles = {
1151                int(char_id): self._deserialize_collectible(data)
1152                for char_id, data in raw_character_collectibles["data"].items()
1153            }
1154
1155        profile_collectibles: items.Collectible | None = None
1156        if raw_profile_collectibles := payload.get("profileCollectibles"):
1157            profile_collectibles = self._deserialize_collectible(
1158                raw_profile_collectibles["data"]
1159            )
1160
1161        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1162        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1163            profile_nodes = {
1164                int(node_hash): self._deserialize_node(node)
1165                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1166            }
1167
1168        character_nodes: typing.Optional[
1169            collections.Mapping[int, collections.Mapping[int, records.Node]]
1170        ] = None
1171        if raw_character_nodes := payload.get("characterPresentationNodes"):
1172            character_nodes = {
1173                int(char_id): {
1174                    int(node_hash): self._deserialize_node(node)
1175                    for node_hash, node in each_character["nodes"].items()
1176                }
1177                for char_id, each_character in raw_character_nodes["data"].items()
1178            }
1179
1180        platform_silver: typing.Optional[
1181            collections.Mapping[str, profile.ProfileItemImpl]
1182        ] = None
1183        if raw_platform_silver := payload.get("platformSilver"):
1184            if "data" in raw_platform_silver:
1185                platform_silver = {
1186                    platform_name: self.deserialize_profile_item(item)
1187                    for platform_name, item in raw_platform_silver["data"][
1188                        "platformSilver"
1189                    ].items()
1190                }
1191
1192        character_currency_lookups: typing.Optional[
1193            collections.Mapping[int, collections.Sequence[items.Currency]]
1194        ] = None
1195        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1196            if "data" in raw_char_lookups:
1197                character_currency_lookups = {
1198                    int(char_id): self._deserialize_currencies(currency)
1199                    for char_id, currency in raw_char_lookups["data"].items()
1200                }
1201
1202        character_craftables: typing.Optional[
1203            collections.Mapping[int, components.CraftablesComponent]
1204        ] = None
1205        if raw_character_craftables := payload.get("characterCraftables"):
1206            if "data" in raw_character_craftables:
1207                character_craftables = {
1208                    int(char_id): self.deserialize_craftables_component(craftable)
1209                    for char_id, craftable in raw_character_craftables["data"].items()
1210                }
1211
1212        return components.Component(
1213            profiles=profile_,
1214            profile_progression=profile_progression,
1215            profile_currencies=profile_currencies,
1216            profile_inventories=profile_inventories,
1217            profile_records=profile_records,
1218            characters=characters,
1219            character_records=character_records,
1220            character_equipments=character_equipments,
1221            character_inventories=character_inventories,
1222            character_activities=character_activities,
1223            character_render_data=character_render_data,
1224            character_progressions=character_progressions,
1225            profile_string_variables=profile_string_vars,
1226            character_string_variables=character_string_vars,
1227            metrics=metrics,
1228            root_node_hash=root_node_hash,
1229            transitory=transitory,
1230            item_components=item_components,
1231            profile_plugsets=profile_plugsets,
1232            character_plugsets=character_plugsets,
1233            character_collectibles=character_collectibles,
1234            profile_collectibles=profile_collectibles,
1235            profile_nodes=profile_nodes,
1236            character_nodes=character_nodes,
1237            platform_silver=platform_silver,
1238            character_currency_lookups=character_currency_lookups,
1239            character_craftables=character_craftables,
1240        )
1241
1242    def deserialize_items_component(
1243        self, payload: typedefs.JSONObject
1244    ) -> components.ItemsComponent:
1245        # Due to how complex this method is, We'll stick to typing.Optional.
1246        instances: typing.Optional[
1247            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1248        ] = None
1249        if raw_instances := payload.get("instances"):
1250            instances = tuple(
1251                {int(ins_id): self.deserialize_instanced_item(item)}
1252                for ins_id, item in raw_instances["data"].items()
1253            )
1254
1255        render_data: typing.Optional[
1256            collections.Mapping[int, tuple[bool, dict[int, int]]]
1257        ] = None
1258        if raw_render_data := payload.get("renderData"):
1259            render_data = {
1260                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1261                for ins_id, data in raw_render_data["data"].items()
1262            }
1263
1264        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1265        if raw_stats := payload.get("stats"):
1266            stats = {}
1267            for ins_id, stat in raw_stats["data"].items():
1268                for _, items_ in stat.items():
1269                    stats[int(ins_id)] = self.deserialize_item_stats_view(items_)
1270
1271        sockets: typing.Optional[
1272            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1273        ] = None
1274        if raw_sockets := payload.get("sockets"):
1275            sockets = {
1276                int(ins_id): tuple(
1277                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1278                )
1279                for ins_id, item in raw_sockets["data"].items()
1280            }
1281
1282        objectives: typing.Optional[
1283            collections.Mapping[int, collections.Sequence[records.Objective]]
1284        ] = None
1285        if raw_objectives := payload.get("objectives"):
1286            objectives = {
1287                int(ins_id): tuple(
1288                    self.deserialize_objectives(objective)
1289                    for objective in data["objectives"]
1290                )
1291                for ins_id, data in raw_objectives["data"].items()
1292            }
1293
1294        perks: typing.Optional[
1295            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1296        ] = None
1297        if raw_perks := payload.get("perks"):
1298            perks = {
1299                int(ins_id): tuple(
1300                    self.deserialize_item_perk(perk) for perk in item["perks"]
1301                )
1302                for ins_id, item in raw_perks["data"].items()
1303            }
1304
1305        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1306        if raw_plug_states := payload.get("plugStates"):
1307            plug_states = tuple(
1308                self.deserialize_plug_item_state(plug)
1309                for _, plug in raw_plug_states["data"].items()
1310            )
1311
1312        reusable_plugs: typing.Optional[
1313            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1314        ] = None
1315        if raw_re_plugs := payload.get("reusablePlugs"):
1316            reusable_plugs = {
1317                int(ins_id): tuple(
1318                    self.deserialize_plug_item_state(state) for state in inner
1319                )
1320                for ins_id, plug in raw_re_plugs["data"].items()
1321                for inner in tuple(plug["plugs"].values())
1322            }
1323
1324        plug_objectives: typing.Optional[
1325            collections.Mapping[
1326                int, collections.Mapping[int, collections.Collection[records.Objective]]
1327            ]
1328        ] = None
1329        if raw_plug_objectives := payload.get("plugObjectives"):
1330            plug_objectives = {
1331                int(ins_id): {
1332                    int(obj_hash): tuple(
1333                        self.deserialize_objectives(obj) for obj in objs
1334                    )
1335                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1336                }
1337                for ins_id, inner in raw_plug_objectives["data"].items()
1338            }
1339
1340        return components.ItemsComponent(
1341            sockets=sockets,
1342            stats=stats,
1343            render_data=render_data,
1344            instances=instances,
1345            objectives=objectives,
1346            perks=perks,
1347            plug_states=plug_states,
1348            reusable_plugs=reusable_plugs,
1349            plug_objectives=plug_objectives,
1350        )
1351
1352    def deserialize_character_component(
1353        self, payload: typedefs.JSONObject
1354    ) -> components.CharacterComponent:
1355        character_: character.Character | None = None
1356        if raw_singular_character := payload.get("character"):
1357            character_ = self.deserialize_character(raw_singular_character["data"])
1358
1359        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1360        if raw_inventory := payload.get("inventory"):
1361            if "data" in raw_inventory:
1362                inventory = self.deserialize_profile_items(raw_inventory["data"])
1363
1364        activities: activity.CharacterActivity | None = None
1365        if raw_activities := payload.get("activities"):
1366            activities = self.deserialize_character_activity(raw_activities["data"])
1367
1368        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1369        if raw_equipments := payload.get("equipment"):
1370            equipment = self.deserialize_profile_items(raw_equipments["data"])
1371
1372        progressions_: character.CharacterProgression | None = None
1373        if raw_progressions := payload.get("progressions"):
1374            progressions_ = self.deserialize_character_progressions(
1375                raw_progressions["data"]
1376            )
1377
1378        render_data: character.RenderedData | None = None
1379        if raw_render_data := payload.get("renderData"):
1380            render_data = self.deserialize_character_render_data(
1381                raw_render_data["data"]
1382            )
1383
1384        character_records: typing.Optional[
1385            collections.Mapping[int, records.CharacterRecord]
1386        ] = None
1387        if raw_char_records := payload.get("records"):
1388            character_records = self.deserialize_characters_records(
1389                raw_char_records["data"]
1390            )
1391
1392        item_components: components.ItemsComponent | None = None
1393        if raw_item_components := payload.get("itemComponents"):
1394            item_components = self.deserialize_items_component(raw_item_components)
1395
1396        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1397        if raw_nodes := payload.get("presentationNodes"):
1398            nodes = {
1399                int(node_hash): self._deserialize_node(node)
1400                for node_hash, node in raw_nodes["data"]["nodes"].items()
1401            }
1402
1403        collectibles: items.Collectible | None = None
1404        if raw_collectibles := payload.get("collectibles"):
1405            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1406
1407        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1408        if raw_currencies := payload.get("currencyLookups"):
1409            if "data" in raw_currencies:
1410                currency_lookups = self._deserialize_currencies(raw_currencies)
1411
1412        return components.CharacterComponent(
1413            activities=activities,
1414            equipment=equipment,
1415            inventory=inventory,
1416            progressions=progressions_,
1417            render_data=render_data,
1418            character=character_,
1419            character_records=character_records,
1420            profile_records=None,
1421            item_components=item_components,
1422            currency_lookups=currency_lookups,
1423            collectibles=collectibles,
1424            nodes=nodes,
1425        )
1426
1427    def _set_entity_attrs(
1428        self, payload: typedefs.JSONObject, *, key: str = "displayProperties"
1429    ) -> entity.Entity:
1430        properties = payload[key]
1431        name = typedefs.unknown(properties["name"])
1432        description = typedefs.unknown(properties["description"])
1433
1434        return entity.Entity(
1435            net=self._net,
1436            hash=payload["hash"],
1437            index=payload["index"],
1438            name=name,
1439            description=description,
1440            has_icon=properties["hasIcon"],
1441            icon=assets.Image.default_or_else(properties.get("icon")),
1442        )
1443
1444    def deserialize_inventory_results(
1445        self, payload: typedefs.JSONObject
1446    ) -> iterators.Iterator[entity.SearchableEntity]:
1447        return iterators.Iterator(
1448            [
1449                entity.SearchableEntity(
1450                    net=self._net,
1451                    hash=data["hash"],
1452                    entity_type=data["entityType"],
1453                    weight=data["weight"],
1454                    suggested_words=payload["suggestedWords"],
1455                    name=data["displayProperties"]["name"],
1456                    has_icon=data["displayProperties"]["hasIcon"],
1457                    description=typedefs.unknown(
1458                        data["displayProperties"]["description"]
1459                    ),
1460                    icon=assets.Image(path=data["displayProperties"]["icon"]),
1461                )
1462                for data in payload["results"]["results"]
1463            ]
1464        )
1465
1466    def _deserialize_inventory_item_objects(
1467        self, payload: typedefs.JSONObject
1468    ) -> entity.InventoryEntityObjects:
1469        return entity.InventoryEntityObjects(
1470            action=payload.get("action"),
1471            set_data=payload.get("setData"),
1472            stats=payload.get("stats"),
1473            equipping_block=payload.get("equippingBlock"),
1474            translation_block=payload.get("translationBlock"),
1475            preview=payload.get("preview"),
1476            quality=payload.get("quality"),
1477            value=payload.get("value"),
1478            source_data=payload.get("sourceData"),
1479            objectives=payload.get("objectives"),
1480            plug=payload.get("plug"),
1481            metrics=payload.get("metrics"),
1482            gearset=payload.get("gearset"),
1483            sack=payload.get("sack"),
1484            sockets=payload.get("sockets"),
1485            summary=payload.get("summary"),
1486            talent_gird=payload.get("talentGrid"),
1487            investments_stats=payload.get("investmentStats"),
1488            perks=payload.get("perks"),
1489            animations=payload.get("animations", ()),
1490            links=payload.get("links", ()),
1491        )
1492
1493    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1494        self, payload: typedefs.JSONObject, /
1495    ) -> entity.InventoryEntity:
1496        props = self._set_entity_attrs(payload)
1497        objects = self._deserialize_inventory_item_objects(payload)
1498
1499        collectible_hash: int | None = None
1500        if raw_collectible_hash := payload.get("collectibleHash"):
1501            collectible_hash = int(raw_collectible_hash)
1502
1503        secondary_icon: assets.Image | None = None
1504        if raw_second_icon := payload.get("secondaryIcon"):
1505            secondary_icon = assets.Image(path=raw_second_icon)
1506
1507        secondary_overlay: assets.Image | None = None
1508        if raw_second_overlay := payload.get("secondaryOverlay"):
1509            secondary_overlay = assets.Image(path=raw_second_overlay)
1510
1511        secondary_special: assets.Image | None = None
1512        if raw_second_special := payload.get("secondarySpecial"):
1513            secondary_special = assets.Image(path=raw_second_special)
1514
1515        screenshot: assets.Image | None = None
1516        if raw_screenshot := payload.get("screenshot"):
1517            screenshot = assets.Image(path=raw_screenshot)
1518
1519        watermark_icon: assets.Image | None = None
1520        if raw_watermark_icon := payload.get("iconWatermark"):
1521            watermark_icon = assets.Image(path=raw_watermark_icon)
1522
1523        watermark_shelved: assets.Image | None = None
1524        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1525            watermark_shelved = assets.Image(path=raw_watermark_shelved)
1526
1527        about: str | None = None
1528        if raw_about := payload.get("flavorText"):
1529            about = raw_about
1530
1531        ui_item_style: str | None = None
1532        if raw_ui_style := payload.get("uiItemDisplayStyle"):
1533            ui_item_style = raw_ui_style
1534
1535        tier_and_name: str | None = None
1536        if raw_tier_and_name := payload.get("itemTypeAndTierDisplayName"):
1537            tier_and_name = raw_tier_and_name
1538
1539        type_name: str | None = None
1540        if raw_type_name := payload.get("itemTypeDisplayName"):
1541            type_name = raw_type_name
1542
1543        display_source: str | None = None
1544        if raw_display_source := payload.get("displaySource"):
1545            display_source = raw_display_source
1546
1547        lorehash: int | None = None
1548        if raw_lore_hash := payload.get("loreHash"):
1549            lorehash = int(raw_lore_hash)
1550
1551        summary_hash: int | None = None
1552        if raw_summary_hash := payload.get("summaryItemHash"):
1553            summary_hash = raw_summary_hash
1554
1555        breaker_type_hash: int | None = None
1556        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1557            breaker_type_hash = int(raw_breaker_type_hash)
1558
1559        damage_types: typing.Optional[collections.Sequence[int]] = None
1560        if raw_damage_types := payload.get("damageTypes"):
1561            damage_types = tuple(int(type_) for type_ in raw_damage_types)
1562
1563        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1564        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1565            damagetype_hashes = tuple(int(type_) for type_ in raw_damagetype_hashes)
1566
1567        default_damagetype_hash: int | None = None
1568        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1569            default_damagetype_hash = int(raw_defaultdmg_hash)
1570
1571        emblem_objective_hash: int | None = None
1572        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1573            emblem_objective_hash = int(raw_emblem_obj_hash)
1574
1575        tier_type: enums.TierType | None = None
1576        tier: enums.ItemTier | None = None
1577        bucket_hash: int | None = None
1578        recovery_hash: int | None = None
1579        tier_name: str | None = None
1580        isinstance_item: bool = False
1581        expire_tool_tip: str | None = None
1582        expire_in_orbit_message: str | None = None
1583        suppress_expiration: bool = False
1584        max_stack_size: int | None = None
1585        stack_label: str | None = None
1586
1587        if inventory := payload.get("inventory"):
1588            tier_type = enums.TierType(int(inventory["tierType"]))
1589            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1590            bucket_hash = int(inventory["bucketTypeHash"])
1591            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1592            tier_name = inventory["tierTypeName"]
1593            isinstance_item = inventory["isInstanceItem"]
1594            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1595            max_stack_size = int(inventory["maxStackSize"])
1596
1597            try:
1598                stack_label = inventory["stackUniqueLabel"]
1599            except KeyError:
1600                pass
1601
1602        if "traitHashes" in payload:
1603            trait_hashes = tuple(
1604                int(trait_hash) for trait_hash in payload["traitHashes"]
1605            )
1606        else:
1607            trait_hashes = ()
1608
1609        if "traitIds" in payload:
1610            trait_ids = tuple(trait_id for trait_id in payload["traitIds"])
1611        else:
1612            trait_ids = ()
1613
1614        return entity.InventoryEntity(
1615            net=self._net,
1616            collectible_hash=collectible_hash,
1617            name=props.name,
1618            about=about,
1619            emblem_objective_hash=emblem_objective_hash,
1620            suppress_expiration=suppress_expiration,
1621            max_stack_size=max_stack_size,
1622            stack_label=stack_label,
1623            tier=tier,
1624            tier_type=tier_type,
1625            tier_name=tier_name,
1626            bucket_hash=bucket_hash,
1627            recovery_bucket_hash=recovery_hash,
1628            isinstance_item=isinstance_item,
1629            expire_in_orbit_message=expire_in_orbit_message,
1630            expiration_tooltip=expire_tool_tip,
1631            lore_hash=lorehash,
1632            type_and_tier_name=tier_and_name,
1633            summary_hash=summary_hash,
1634            ui_display_style=ui_item_style,
1635            type_name=type_name,
1636            breaker_type_hash=breaker_type_hash,
1637            description=props.description,
1638            display_source=display_source,
1639            hash=props.hash,
1640            damage_types=damage_types,
1641            index=props.index,
1642            icon=props.icon,
1643            has_icon=props.has_icon,
1644            screenshot=screenshot,
1645            watermark_icon=watermark_icon,
1646            watermark_shelved=watermark_shelved,
1647            secondary_icon=secondary_icon,
1648            secondary_overlay=secondary_overlay,
1649            secondary_special=secondary_special,
1650            type=enums.ItemType(int(payload["itemType"])),
1651            category_hashes=tuple(
1652                int(hash_) for hash_ in payload["itemCategoryHashes"]
1653            ),
1654            item_class=enums.Class(int(payload["classType"])),
1655            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1656            breaker_type=int(payload["breakerType"]),
1657            default_damagetype=int(payload["defaultDamageType"]),
1658            default_damagetype_hash=default_damagetype_hash,
1659            damagetype_hashes=damagetype_hashes,
1660            tooltip_notifications=payload["tooltipNotifications"],
1661            not_transferable=payload["nonTransferrable"],
1662            allow_actions=payload["allowActions"],
1663            is_equippable=payload["equippable"],
1664            objects=objects,
1665            background_colors=payload.get("backgroundColor", {}),
1666            season_hash=payload.get("seasonHash"),
1667            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1668            trait_hashes=trait_hashes,
1669            trait_ids=trait_ids,
1670        )
1671
1672    def deserialize_objective_entity(
1673        self, payload: typedefs.JSONObject, /
1674    ) -> entity.ObjectiveEntity:
1675        props = self._set_entity_attrs(payload)
1676        return entity.ObjectiveEntity(
1677            net=self._net,
1678            hash=props.hash,
1679            index=props.index,
1680            description=props.description,
1681            name=props.name,
1682            has_icon=props.has_icon,
1683            icon=props.icon,
1684            unlock_value_hash=payload["unlockValueHash"],
1685            completion_value=payload["completionValue"],
1686            scope=entity.GatingScope(int(payload["scope"])),
1687            location_hash=payload["locationHash"],
1688            allowed_negative_value=payload["allowNegativeValue"],
1689            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1690            counting_downward=payload["isCountingDownward"],
1691            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1692            progress_description=payload["progressDescription"],
1693            perks=payload["perks"],
1694            stats=payload["stats"],
1695            minimum_visibility=payload["minimumVisibilityThreshold"],
1696            allow_over_completion=payload["allowOvercompletion"],
1697            show_value_style=payload["showValueOnComplete"],
1698            display_only_objective=payload["isDisplayOnlyObjective"],
1699            complete_value_style=entity.ValueUIStyle(
1700                int(payload["completedValueStyle"])
1701            ),
1702            progress_value_style=entity.ValueUIStyle(
1703                int(payload["inProgressValueStyle"])
1704            ),
1705            ui_label=payload["uiLabel"],
1706            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1707        )
1708
1709    def _deserialize_activity_values(
1710        self, payload: typedefs.JSONObject, /
1711    ) -> activity.ActivityValues:
1712        team: int | None = None
1713        if raw_team := payload.get("team"):
1714            team = raw_team["basic"]["value"]
1715        return activity.ActivityValues(
1716            assists=payload["assists"]["basic"]["value"],
1717            deaths=payload["deaths"]["basic"]["value"],
1718            kills=payload["kills"]["basic"]["value"],
1719            is_completed=bool(payload["completed"]["basic"]["value"]),
1720            opponents_defeated=payload["opponentsDefeated"]["basic"]["value"],
1721            efficiency=payload["efficiency"]["basic"]["value"],
1722            kd_ratio=payload["killsDeathsRatio"]["basic"]["value"],
1723            kd_assists=payload["killsDeathsAssists"]["basic"]["value"],
1724            score=payload["score"]["basic"]["value"],
1725            duration=payload["activityDurationSeconds"]["basic"]["displayValue"],
1726            team=team,
1727            completion_reason=payload["completionReason"]["basic"]["displayValue"],
1728            fireteam_id=payload["fireteamId"]["basic"]["value"],
1729            start_seconds=payload["startSeconds"]["basic"]["value"],
1730            played_time=payload["timePlayedSeconds"]["basic"]["displayValue"],
1731            player_count=payload["playerCount"]["basic"]["value"],
1732            team_score=payload["teamScore"]["basic"]["value"],
1733        )
1734
1735    def deserialize_activity(
1736        self,
1737        payload: typedefs.JSONObject,
1738        /,
1739    ) -> activity.Activity:
1740        period = time.clean_date(payload["period"])
1741        details = payload["activityDetails"]
1742        ref_id = int(details["referenceId"])
1743        instance_id = int(details["instanceId"])
1744        mode = enums.GameMode(details["mode"])
1745        modes = tuple(enums.GameMode(int(mode_)) for mode_ in details["modes"])
1746        is_private = details["isPrivate"]
1747        membership_type = enums.MembershipType(int(details["membershipType"]))
1748
1749        # Since we're using the same fields for post activity method
1750        # this check is required since post activity doesn't values values
1751        values = self._deserialize_activity_values(payload["values"])
1752
1753        return activity.Activity(
1754            net=self._net,
1755            hash=ref_id,
1756            instance_id=instance_id,
1757            mode=mode,
1758            modes=modes,
1759            is_private=is_private,
1760            membership_type=membership_type,
1761            occurred_at=period,
1762            values=values,
1763        )
1764
1765    def deserialize_activities(
1766        self, payload: typedefs.JSONObject
1767    ) -> iterators.Iterator[activity.Activity]:
1768        return iterators.Iterator(
1769            [
1770                self.deserialize_activity(activity_)
1771                for activity_ in payload["activities"]
1772            ]
1773        )
1774
1775    def deserialize_extended_weapon_values(
1776        self, payload: typedefs.JSONObject
1777    ) -> activity.ExtendedWeaponValues:
1778        assists: int | None = None
1779        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1780            assists = raw_assists["basic"]["value"]
1781        assists_damage: int | None = None
1782
1783        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1784            assists_damage = raw_assists_damage["basic"]["value"]
1785
1786        return activity.ExtendedWeaponValues(
1787            reference_id=int(payload["referenceId"]),
1788            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1789            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1790                "value"
1791            ],
1792            assists=assists,
1793            assists_damage=assists_damage,
1794            precision_kills_percentage=(
1795                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1796                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1797                    "displayValue"
1798                ],
1799            ),
1800        )
1801
1802    def _deserialize_extended_values(
1803        self, payload: typedefs.JSONObject
1804    ) -> activity.ExtendedValues:
1805        if raw_weapons := payload.get("weapons"):
1806            weapons = tuple(
1807                self.deserialize_extended_weapon_values(value) for value in raw_weapons
1808            )
1809        else:
1810            weapons = ()
1811
1812        return activity.ExtendedValues(
1813            precision_kills=payload["values"]["precisionKills"]["basic"]["value"],
1814            grenade_kills=payload["values"]["weaponKillsGrenade"]["basic"]["value"],
1815            melee_kills=payload["values"]["weaponKillsMelee"]["basic"]["value"],
1816            super_kills=payload["values"]["weaponKillsSuper"]["basic"]["value"],
1817            ability_kills=payload["values"]["weaponKillsAbility"]["basic"]["value"],
1818            weapons=weapons,
1819        )
1820
1821    def deserialize_post_activity_player(
1822        self, payload: typedefs.JSONObject, /
1823    ) -> activity.PostActivityPlayer:
1824        player = payload["player"]
1825
1826        class_hash: int | None = None
1827        if (class_hash := player.get("classHash")) is not None:
1828            class_hash = class_hash
1829
1830        race_hash: int | None = None
1831        if (race_hash := player.get("raceHash")) is not None:
1832            race_hash = race_hash
1833
1834        gender_hash: int | None = None
1835        if (gender_hash := player.get("genderHash")) is not None:
1836            gender_hash = gender_hash
1837
1838        character_class: str | None = None
1839        if character_class := player.get("characterClass"):
1840            character_class = character_class
1841
1842        character_level: int | None = None
1843        if (character_level := player.get("characterLevel")) is not None:
1844            character_level = character_level
1845
1846        return activity.PostActivityPlayer(
1847            standing=int(payload["standing"]),
1848            score=int(payload["score"]["basic"]["value"]),
1849            character_id=payload["characterId"],
1850            destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]),
1851            character_class=character_class,
1852            character_level=character_level,
1853            race_hash=race_hash,
1854            gender_hash=gender_hash,
1855            class_hash=class_hash,
1856            light_level=int(player["lightLevel"]),
1857            emblem_hash=int(player["emblemHash"]),
1858            values=self._deserialize_activity_values(payload["values"]),
1859            extended_values=self._deserialize_extended_values(payload["extended"]),
1860        )
1861
1862    def _deserialize_post_activity_team(
1863        self, payload: typedefs.JSONObject
1864    ) -> activity.PostActivityTeam:
1865        return activity.PostActivityTeam(
1866            id=payload["teamId"],
1867            is_defeated=bool(payload["standing"]["basic"]["value"]),
1868            score=int(payload["score"]["basic"]["value"]),
1869            name=payload["teamName"],
1870        )
1871
1872    def deserialize_post_activity(
1873        self, payload: typedefs.JSONObject
1874    ) -> activity.PostActivity:
1875        period = time.clean_date(payload["period"])
1876        details = payload["activityDetails"]
1877        ref_id = int(details["referenceId"])
1878        instance_id = int(details["instanceId"])
1879        mode = enums.GameMode(details["mode"])
1880        modes = tuple(enums.GameMode(int(mode_)) for mode_ in details["modes"])
1881        is_private = details["isPrivate"]
1882        membership_type = enums.MembershipType(int(details["membershipType"]))
1883        return activity.PostActivity(
1884            net=self._net,
1885            hash=ref_id,
1886            membership_type=membership_type,
1887            instance_id=instance_id,
1888            mode=mode,
1889            modes=modes,
1890            is_private=is_private,
1891            occurred_at=period,
1892            starting_phase=int(payload["startingPhaseIndex"]),
1893            players=tuple(
1894                self.deserialize_post_activity_player(player)
1895                for player in payload["entries"]
1896            ),
1897            teams=tuple(
1898                self._deserialize_post_activity_team(team) for team in payload["teams"]
1899            ),
1900        )
1901
1902    def _deserialize_aggregated_activity_values(
1903        self, payload: typedefs.JSONObject
1904    ) -> activity.AggregatedActivityValues:
1905        # This ID is always the same for all aggregated values.
1906        activity_id = int(payload["fastestCompletionMsForActivity"]["activityId"])
1907
1908        return activity.AggregatedActivityValues(
1909            id=activity_id,
1910            fastest_completion_time=(
1911                int(payload["fastestCompletionMsForActivity"]["basic"]["value"]),
1912                payload["fastestCompletionMsForActivity"]["basic"]["displayValue"],
1913            ),
1914            completions=int(payload["activityCompletions"]["basic"]["value"]),
1915            kills=int(payload["activityKills"]["basic"]["value"]),
1916            deaths=int(payload["activityDeaths"]["basic"]["value"]),
1917            assists=int(payload["activityAssists"]["basic"]["value"]),
1918            seconds_played=(
1919                int(payload["activitySecondsPlayed"]["basic"]["value"]),
1920                payload["activitySecondsPlayed"]["basic"]["displayValue"],
1921            ),
1922            wins=int(payload["activityWins"]["basic"]["value"]),
1923            goals_missed=int(payload["activityGoalsMissed"]["basic"]["value"]),
1924            special_actions=int(payload["activitySpecialActions"]["basic"]["value"]),
1925            best_goals_hit=int(payload["activityBestGoalsHit"]["basic"]["value"]),
1926            best_single_score=int(
1927                payload["activityBestSingleGameScore"]["basic"]["value"]
1928            ),
1929            goals_hit=int(payload["activityGoalsHit"]["basic"]["value"]),
1930            special_score=int(payload["activitySpecialScore"]["basic"]["value"]),
1931            kd_assists=int(payload["activityKillsDeathsAssists"]["basic"]["value"]),
1932            kd_ratio=float(
1933                payload["activityKillsDeathsAssists"]["basic"]["displayValue"]
1934            ),
1935            precision_kills=int(payload["activityPrecisionKills"]["basic"]["value"]),
1936        )
1937
1938    def deserialize_aggregated_activity(
1939        self, payload: typedefs.JSONObject
1940    ) -> activity.AggregatedActivity:
1941        return activity.AggregatedActivity(
1942            hash=int(payload["activityHash"]),
1943            values=self._deserialize_aggregated_activity_values(payload["values"]),
1944        )
1945
1946    def deserialize_aggregated_activities(
1947        self, payload: typedefs.JSONObject
1948    ) -> iterators.Iterator[activity.AggregatedActivity]:
1949        return iterators.Iterator(
1950            [
1951                self.deserialize_aggregated_activity(activity)
1952                for activity in payload["activities"]
1953            ]
1954        )
1955
1956    def deserialize_linked_profiles(
1957        self, payload: typedefs.JSONObject
1958    ) -> profile.LinkedProfile:
1959        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
1960
1961        if raw_profile := payload.get("profiles"):
1962            profiles = tuple(
1963                self.deserialize_destiny_membership(p) for p in raw_profile
1964            )
1965        else:
1966            profiles = ()
1967
1968        error_profiles = ()
1969        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
1970            for raw_error_p in raw_profiles_with_errors:
1971                if "infoCard" in raw_error_p:
1972                    error_profiles = tuple(
1973                        self.deserialize_destiny_membership(error_p)
1974                        for error_p in raw_error_p
1975                    )
1976
1977        return profile.LinkedProfile(
1978            bungie_user=bungie_user,
1979            profiles=profiles,
1980            profiles_with_errors=error_profiles,
1981        )
1982
1983    def deserialize_clan_banners(
1984        self, payload: typedefs.JSONObject
1985    ) -> collections.Sequence[clans.ClanBanner]:
1986        if banners := payload.get("clanBannerDecals"):
1987            banner_obj = tuple(
1988                clans.ClanBanner(
1989                    id=int(k),
1990                    foreground=assets.Image(path=v["foregroundPath"]),
1991                    background=assets.Image(path=v["backgroundPath"]),
1992                )
1993                for k, v in banners.items()
1994            )
1995        else:
1996            banner_obj = ()
1997        return banner_obj
1998
1999    def deserialize_public_milestone_content(
2000        self, payload: typedefs.JSONObject
2001    ) -> milestones.MilestoneContent:
2002        if raw_categories := payload.get("itemCategories"):
2003            items_categories = tuple(
2004                milestones.MilestoneItems(
2005                    title=item["title"], hashes=item["itemHashes"]
2006                )
2007                for item in raw_categories
2008            )
2009        else:
2010            items_categories = ()
2011
2012        return milestones.MilestoneContent(
2013            about=typedefs.unknown(payload["about"]),
2014            status=typedefs.unknown(payload["status"]),
2015            tips=payload.get("tips", ()),
2016            items=items_categories,
2017        )
2018
2019    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2020        bungie_user: user.BungieUser | None = None
2021
2022        if raw_bungie_user := payload.get("bungieNetUser"):
2023            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2024
2025        return friends.Friend(
2026            net=self._net,
2027            id=int(payload["lastSeenAsMembershipId"]),
2028            name=typedefs.unknown(payload["bungieGlobalDisplayName"]),
2029            code=payload.get("bungieGlobalDisplayNameCode"),
2030            relationship=enums.Relationship(payload["relationship"]),
2031            user=bungie_user,
2032            online_status=enums.Presence(payload["onlineStatus"]),
2033            online_title=payload["onlineTitle"],
2034            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2035        )
2036
2037    def deserialize_friends(
2038        self, payload: typedefs.JSONObject
2039    ) -> collections.Sequence[friends.Friend]:
2040        return tuple(self.deserialize_friend(friend) for friend in payload["friends"])
2041
2042    def deserialize_friend_requests(
2043        self, payload: typedefs.JSONObject
2044    ) -> friends.FriendRequestView:
2045        if raw_incoming_requests := payload.get("incomingRequests"):
2046            incoming = tuple(
2047                self.deserialize_friend(incoming_request)
2048                for incoming_request in raw_incoming_requests
2049            )
2050        else:
2051            incoming = ()
2052
2053        if raw_outgoing_requests := payload.get("outgoingRequests"):
2054            outgoing = tuple(
2055                self.deserialize_friend(outgoing_request)
2056                for outgoing_request in raw_outgoing_requests
2057            )
2058        else:
2059            outgoing = ()
2060
2061        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)
2062
2063    def _set_fireteam_fields(
2064        self, payload: typedefs.JSONObject, total_results: int | None = None
2065    ) -> fireteams.Fireteam:
2066        activity_type = fireteams.FireteamActivity(payload["activityType"])
2067        return fireteams.Fireteam(
2068            id=int(payload["fireteamId"]),
2069            group_id=int(payload["groupId"]),
2070            platform=fireteams.FireteamPlatform(payload["platform"]),
2071            is_immediate=payload["isImmediate"],
2072            activity_type=activity_type,
2073            owner_id=int(payload["ownerMembershipId"]),
2074            player_slot_count=payload["playerSlotCount"],
2075            available_player_slots=payload["availablePlayerSlotCount"],
2076            available_alternate_slots=payload["availableAlternateSlotCount"],
2077            title=payload["title"],
2078            date_created=time.clean_date(payload["dateCreated"]),
2079            is_public=payload["isPublic"],
2080            locale=fireteams.FireteamLanguage(payload["locale"]),
2081            is_valid=payload["isValid"],
2082            last_modified=time.clean_date(payload["datePlayerModified"]),
2083            date_modified=time.clean_date(payload["dateModified"])
2084            if "dateModified" in payload
2085            else None,
2086            scheduled_time=time.clean_date(payload["scheduledTime"])
2087            if "scheduledTime" in payload
2088            else None,
2089            total_results=total_results or 0,
2090        )
2091
2092    def deserialize_fireteams(
2093        self, payload: typedefs.JSONObject
2094    ) -> collections.Sequence[fireteams.Fireteam]:
2095        if "results" in payload:
2096            fireteams_ = tuple(
2097                self._set_fireteam_fields(
2098                    elem, total_results=int(payload["totalResults"])
2099                )
2100                for elem in payload["results"]
2101            )
2102        else:
2103            fireteams_ = ()
2104        return fireteams_
2105
2106    def deserialize_fireteam_destiny_users(
2107        self, payload: typedefs.JSONObject
2108    ) -> fireteams.FireteamUser:
2109        destiny_obj = self.deserialize_destiny_membership(payload)
2110        return fireteams.FireteamUser(
2111            net=self._net,
2112            id=destiny_obj.id,
2113            code=destiny_obj.code,
2114            icon=destiny_obj.icon,
2115            types=destiny_obj.types,
2116            type=destiny_obj.type,
2117            is_public=destiny_obj.is_public,
2118            crossave_override=destiny_obj.crossave_override,
2119            name=destiny_obj.name,
2120            last_seen_name=destiny_obj.last_seen_name,
2121            fireteam_display_name=payload["FireteamDisplayName"],
2122            fireteam_membership_id=enums.MembershipType(
2123                payload["FireteamMembershipType"]
2124            ),
2125        )
2126
2127    def deserialize_fireteam_members(
2128        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2129    ) -> collections.Sequence[fireteams.FireteamMember]:
2130        members_: list[fireteams.FireteamMember] = []
2131        if members := payload.get("Members" if not alternatives else "Alternates"):
2132            for member in members:
2133                bungie_fields = self.deserialize_partial_bungie_user(member)
2134                members_fields = fireteams.FireteamMember(
2135                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2136                    has_microphone=member["hasMicrophone"],
2137                    character_id=int(member["characterId"]),
2138                    date_joined=time.clean_date(member["dateJoined"]),
2139                    last_platform_invite_date=time.clean_date(
2140                        member["lastPlatformInviteAttemptDate"]
2141                    ),
2142                    last_platform_invite_result=int(
2143                        member["lastPlatformInviteAttemptResult"]
2144                    ),
2145                    net=self._net,
2146                    name=bungie_fields.name,
2147                    id=bungie_fields.id,
2148                    icon=bungie_fields.icon,
2149                    is_public=bungie_fields.is_public,
2150                    crossave_override=bungie_fields.crossave_override,
2151                    types=bungie_fields.types,
2152                    type=bungie_fields.type,
2153                )
2154                members_.append(members_fields)
2155        return tuple(members_)
2156
2157    def deserialize_available_fireteam(
2158        self, payload: typedefs.JSONObject
2159    ) -> fireteams.AvailableFireteam:
2160        fields = self._set_fireteam_fields(payload["Summary"])
2161        return fireteams.AvailableFireteam(
2162            id=fields.id,
2163            group_id=fields.group_id,
2164            platform=fields.platform,
2165            activity_type=fields.activity_type,
2166            is_immediate=fields.is_immediate,
2167            is_public=fields.is_public,
2168            is_valid=fields.is_valid,
2169            owner_id=fields.owner_id,
2170            player_slot_count=fields.player_slot_count,
2171            available_player_slots=fields.available_player_slots,
2172            available_alternate_slots=fields.available_alternate_slots,
2173            title=fields.title,
2174            date_created=fields.date_created,
2175            locale=fields.locale,
2176            last_modified=fields.last_modified,
2177            total_results=fields.total_results,
2178            scheduled_time=fields.scheduled_time,
2179            date_modified=fields.date_modified,
2180            members=self.deserialize_fireteam_members(payload),
2181            alternatives=self.deserialize_fireteam_members(payload, alternatives=True),
2182        )
2183
2184    def deserialize_available_fireteams(
2185        self, data: typedefs.JSONObject
2186    ) -> collections.Sequence[fireteams.AvailableFireteam]:
2187        if raw_results := data.get("results"):
2188            fireteam_results = tuple(
2189                self.deserialize_available_fireteam(f) for f in raw_results
2190            )
2191        else:
2192            fireteam_results = ()
2193        return fireteam_results
2194
2195    def deserialize_fireteam_party(
2196        self, payload: typedefs.JSONObject
2197    ) -> fireteams.FireteamParty:
2198        last_destination_hash: int | None = None
2199        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2200            last_destination_hash = int(raw_dest_hash)
2201
2202        return fireteams.FireteamParty(
2203            members=tuple(
2204                self._deserialize_fireteam_party_member(member)
2205                for member in payload["partyMembers"]
2206            ),
2207            activity=self._deserialize_fireteam_party_current_activity(
2208                payload["currentActivity"]
2209            ),
2210            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2211            last_destination_hash=last_destination_hash,
2212            tracking=payload["tracking"],
2213        )
2214
2215    def _deserialize_fireteam_party_member(
2216        self, payload: typedefs.JSONObject
2217    ) -> fireteams.FireteamPartyMember:
2218        status = fireteams.FireteamPartyMemberState(payload["status"])
2219
2220        return fireteams.FireteamPartyMember(
2221            membership_id=int(payload["membershipId"]),
2222            emblem_hash=int(payload["emblemHash"]),
2223            status=status,
2224            display_name=payload["displayName"] if payload["displayName"] else None,
2225        )
2226
2227    def _deserialize_fireteam_party_current_activity(
2228        self, payload: typedefs.JSONObject
2229    ) -> fireteams.FireteamPartyCurrentActivity:
2230        start_date: datetime.datetime | None = None
2231        if raw_start_date := payload.get("startTime"):
2232            start_date = time.clean_date(raw_start_date)
2233
2234        end_date: datetime.datetime | None = None
2235        if raw_end_date := payload.get("endTime"):
2236            end_date = time.clean_date(raw_end_date)
2237        return fireteams.FireteamPartyCurrentActivity(
2238            start_time=start_date,
2239            end_time=end_date,
2240            score=float(payload["score"]),
2241            highest_opposing_score=float(payload["highestOpposingFactionScore"]),
2242            opponents_count=int(payload["numberOfOpponents"]),
2243            player_count=int(payload["numberOfPlayers"]),
2244        )
2245
2246    def _deserialize_fireteam_party_settings(
2247        self, payload: typedefs.JSONObject
2248    ) -> fireteams.FireteamPartySettings:
2249        closed_reasons = enums.ClosedReasons(payload["closedReasons"])
2250        return fireteams.FireteamPartySettings(
2251            open_slots=int(payload["openSlots"]),
2252            privacy_setting=enums.PrivacySetting(int(payload["privacySetting"])),
2253            closed_reasons=closed_reasons,
2254        )
2255
2256    def deserialize_seasonal_artifact(
2257        self, payload: typedefs.JSONObject
2258    ) -> season.Artifact:
2259        raw_artifact = payload["seasonalArtifact"]
2260
2261        points = raw_artifact["pointProgression"]
2262        points_prog = progressions.Progression(
2263            hash=points["progressionHash"],
2264            level=points["level"],
2265            cap=points["levelCap"],
2266            daily_limit=points["dailyLimit"],
2267            weekly_limit=points["weeklyLimit"],
2268            current_progress=points["currentProgress"],
2269            daily_progress=points["dailyProgress"],
2270            needed=points["progressToNextLevel"],
2271            next_level=points["nextLevelAt"],
2272        )
2273
2274        bonus = raw_artifact["powerBonusProgression"]
2275        power_bonus_prog = progressions.Progression(
2276            hash=bonus["progressionHash"],
2277            level=bonus["level"],
2278            cap=bonus["levelCap"],
2279            daily_limit=bonus["dailyLimit"],
2280            weekly_limit=bonus["weeklyLimit"],
2281            current_progress=bonus["currentProgress"],
2282            daily_progress=bonus["dailyProgress"],
2283            needed=bonus["progressToNextLevel"],
2284            next_level=bonus["nextLevelAt"],
2285        )
2286        return season.Artifact(
2287            hash=raw_artifact["artifactHash"],
2288            power_bonus=raw_artifact["powerBonus"],
2289            acquired_points=raw_artifact["pointsAcquired"],
2290            bonus=power_bonus_prog,
2291            points=points_prog,
2292        )
2293
2294    def deserialize_profile_progression(
2295        self, payload: typedefs.JSONObject
2296    ) -> profile.ProfileProgression:
2297        return profile.ProfileProgression(
2298            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2299            checklist={
2300                int(check_id): checklists
2301                for check_id, checklists in payload["data"]["checklists"].items()
2302            },
2303        )
2304
2305    def deserialize_instanced_item(
2306        self, payload: typedefs.JSONObject
2307    ) -> items.ItemInstance:
2308        damage_type_hash: int | None = None
2309        if raw_damagetype_hash := payload.get("damageTypeHash"):
2310            damage_type_hash = int(raw_damagetype_hash)
2311
2312        required_hashes: typing.Optional[collections.Collection[int]] = None
2313        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2314            required_hashes = tuple(int(raw_hash) for raw_hash in raw_required_hashes)
2315
2316        breaker_type: items.ItemBreakerType | None = None
2317        if raw_break_type := payload.get("breakerType"):
2318            breaker_type = items.ItemBreakerType(int(raw_break_type))
2319
2320        breaker_type_hash: int | None = None
2321        if raw_break_type_hash := payload.get("breakerTypeHash"):
2322            breaker_type_hash = int(raw_break_type_hash)
2323
2324        energy: items.ItemEnergy | None = None
2325        if raw_energy := payload.get("energy"):
2326            energy = self.deserialize_item_energy(raw_energy)
2327
2328        primary_stats = None
2329        if raw_primary_stats := payload.get("primaryStat"):
2330            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2331
2332        return items.ItemInstance(
2333            damage_type=enums.DamageType(int(payload["damageType"])),
2334            damage_type_hash=damage_type_hash,
2335            primary_stat=primary_stats,
2336            item_level=int(payload["itemLevel"]),
2337            quality=int(payload["quality"]),
2338            is_equipped=payload["isEquipped"],
2339            can_equip=payload["canEquip"],
2340            equip_required_level=int(payload["equipRequiredLevel"]),
2341            required_equip_unlock_hashes=required_hashes,
2342            cant_equip_reason=int(payload["cannotEquipReason"]),
2343            breaker_type=breaker_type,
2344            breaker_type_hash=breaker_type_hash,
2345            energy=energy,
2346        )
2347
2348    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2349        energy_hash: int | None = None
2350        if raw_energy_hash := payload.get("energyTypeHash"):
2351            energy_hash = int(raw_energy_hash)
2352
2353        return items.ItemEnergy(
2354            hash=energy_hash,
2355            type=items.ItemEnergyType(int(payload["energyType"])),
2356            capacity=int(payload["energyCapacity"]),
2357            used_energy=int(payload["energyUsed"]),
2358            unused_energy=int(payload["energyUnused"]),
2359        )
2360
2361    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2362        perk_hash: int | None = None
2363        if raw_perk_hash := payload.get("perkHash"):
2364            perk_hash = int(raw_perk_hash)
2365
2366        return items.ItemPerk(
2367            hash=perk_hash,
2368            icon=assets.Image(path=payload["iconPath"]),
2369            is_active=payload["isActive"],
2370            is_visible=payload["visible"],
2371        )
2372
2373    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2374        plug_hash: int | None = None
2375        if raw_plug_hash := payload.get("plugHash"):
2376            plug_hash = int(raw_plug_hash)
2377
2378        enable_fail_indexes: collections.Sequence[int] | None = None
2379        if raw_indexes := payload.get("enableFailIndexes"):
2380            enable_fail_indexes = tuple(int(index) for index in raw_indexes)
2381
2382        return items.ItemSocket(
2383            plug_hash=plug_hash,
2384            is_enabled=payload["isEnabled"],
2385            enable_fail_indexes=enable_fail_indexes,
2386            is_visible=payload.get("visible"),
2387        )
2388
2389    def deserialize_item_stats_view(
2390        self, payload: typedefs.JSONObject
2391    ) -> items.ItemStatsView:
2392        return items.ItemStatsView(
2393            stat_hash=payload.get("statHash"), value=payload.get("value")
2394        )
2395
2396    def deserialize_plug_item_state(
2397        self, payload: typedefs.JSONObject
2398    ) -> items.PlugItemState:
2399        item_hash: int | None = None
2400        if raw_item_hash := payload.get("plugItemHash"):
2401            item_hash = int(raw_item_hash)
2402
2403        insert_fail_indexes: collections.Sequence[int] | None = None
2404        if raw_fail_indexes := payload.get("insertFailIndexes"):
2405            insert_fail_indexes = tuple(int(k) for k in raw_fail_indexes)
2406
2407        enable_fail_indexes: collections.Sequence[int] | None = None
2408        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2409            enable_fail_indexes = tuple(int(k) for k in raw_enabled_indexes)
2410
2411        return items.PlugItemState(
2412            item_hash=item_hash,
2413            insert_fail_indexes=insert_fail_indexes,
2414            enable_fail_indexes=enable_fail_indexes,
2415            is_enabled=payload["enabled"],
2416            can_insert=payload["canInsert"],
2417        )

The base deserialization factory class for all aiobungie objects.

This entity factory is used to deserialize JSON responses from the REST client and turning them into a aiobungie.crates Python classes.

Factory(net: aiobungie.traits.Netrunner)
69    def __init__(self, net: traits.Netrunner) -> None:
70        self._net = net
def deserialize_bungie_user( self, data: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.user.BungieUser:
72    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
73        return user.BungieUser(
74            id=int(data["membershipId"]),
75            created_at=time.clean_date(data["firstAccess"]),
76            name=data.get("cachedBungieGlobalDisplayName"),
77            is_deleted=data["isDeleted"],
78            about=data["about"],
79            updated_at=time.clean_date(data["lastUpdate"]),
80            psn_name=data.get("psnDisplayName", None),
81            stadia_name=data.get("stadiaDisplayName", None),
82            steam_name=data.get("steamDisplayName", None),
83            twitch_name=data.get("twitchDisplayName", None),
84            blizzard_name=data.get("blizzardDisplayName", None),
85            status=data["statusText"],
86            locale=data["locale"],
87            picture=assets.Image(path=data["profilePicturePath"]),
88            code=data.get("cachedBungieGlobalDisplayNameCode", None),
89            unique_name=data.get("uniqueName", None),
90            theme_id=int(data["profileTheme"]),
91            show_activity=bool(data["showActivity"]),
92            theme_name=data["profileThemeName"],
93            display_title=data["userTitleDisplay"],
94        )

Deserialize a raw JSON Bungie.net user only payload into a user object.

This only returns the Bungie.net user and not the Destiny memberships.

Parameters
Returns
def deserialize_partial_bungie_user( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.user.PartialBungieUser:
 96    def deserialize_partial_bungie_user(
 97        self, payload: typedefs.JSONObject
 98    ) -> user.PartialBungieUser:
 99        return user.PartialBungieUser(
100            net=self._net,
101            types=tuple(
102                enums.MembershipType(type_)
103                for type_ in payload.get("applicableMembershipTypes", ())
104            ),
105            name=payload.get("displayName"),
106            id=int(payload["membershipId"]),
107            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
108            is_public=payload["isPublic"],
109            icon=assets.Image(path=payload.get("iconPath", "")),
110            type=enums.MembershipType(payload["membershipType"]),
111        )

Deserialize a raw JSON of a partial bungieNetUserInfo.

A partial user is a bungie.net user payload with missing information from the main BungieUser object.

Parameters
Returns
def deserialize_destiny_membership( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.user.DestinyMembership:
113    def deserialize_destiny_membership(
114        self, payload: typedefs.JSONObject
115    ) -> user.DestinyMembership:
116        name: str | None = None
117        if (raw_name := payload.get("bungieGlobalDisplayName")) is not None:
118            name = typedefs.unknown(raw_name)
119
120        return user.DestinyMembership(
121            net=self._net,
122            id=int(payload["membershipId"]),
123            name=name,
124            code=payload.get("bungieGlobalDisplayNameCode", None),
125            last_seen_name=payload.get("LastSeenDisplayName")
126            or payload.get("displayName")  # noqa: W503
127            or "",  # noqa: W503
128            type=enums.MembershipType(payload["membershipType"]),
129            is_public=payload["isPublic"],
130            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
131            icon=assets.Image(path=payload.get("iconPath", "")),
132            types=tuple(
133                enums.MembershipType(type_)
134                for type_ in payload.get("applicableMembershipTypes", ())
135            ),
136        )

Deserialize a raw JSON of destinyUserInfo destiny membership information.

Parameters
Returns
  • aiobungie.crates.user.DestinyMembership: A Destiny 2 membership.
def deserialize_destiny_memberships( self, data: collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
138    def deserialize_destiny_memberships(
139        self, data: typedefs.JSONArray
140    ) -> collections.Sequence[user.DestinyMembership]:
141        return tuple(
142            self.deserialize_destiny_membership(membership) for membership in data
143        )

Deserialize a raw JSON payload/array of destinyUserInfo.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.DestinyMembership]: A sequence of Destiny 2 memberships.
def deserialize_user( self, data: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.user.User:
145    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
146        primary_membership_id: int | None = None
147        if raw_primary_id := data.get("primaryMembershipId"):
148            primary_membership_id = int(raw_primary_id)
149
150        return user.User(
151            bungie_user=self.deserialize_bungie_user(data["bungieNetUser"]),
152            memberships=self.deserialize_destiny_memberships(
153                data["destinyMemberships"]
154            ),
155            primary_membership_id=primary_membership_id,
156        )

Deserialize a raw JSON results of fetched user memberships and Bungie.net user its their id.

Parameters
Returns
def deserialize_searched_user( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.user.SearchableDestinyUser:
158    def deserialize_searched_user(
159        self, payload: typedefs.JSONObject
160    ) -> user.SearchableDestinyUser:
161        code: int | None = None
162        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
163            code = int(raw_code)
164
165        bungie_id: int | None = None
166        if raw_bungie_id := payload.get("bungieNetMembershipId"):
167            bungie_id = int(raw_bungie_id)
168
169        return user.SearchableDestinyUser(
170            name=typedefs.unknown(payload["bungieGlobalDisplayName"]),
171            code=code,
172            bungie_id=bungie_id,
173            memberships=self.deserialize_destiny_memberships(
174                payload["destinyMemberships"]
175            ),
176        )

Deserialize the results of user search details.

Parameters
Returns
def deserialize_user_credentials( self, payload: collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
178    def deserialize_user_credentials(
179        self, payload: typedefs.JSONArray
180    ) -> collections.Sequence[user.UserCredentials]:
181        return tuple(
182            user.UserCredentials(
183                type=enums.CredentialType(int(creds["credentialType"])),
184                display_name=creds["credentialDisplayName"],
185                is_public=creds["isPublic"],
186                self_as_string=creds.get("credentialAsString"),
187            )
188            for creds in payload
189        )

Deserialize a JSON array of Bungie user credentials.

Parameters
Returns
def deserialize_user_themes( self, payload: collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
191    def deserialize_user_themes(
192        self, payload: typedefs.JSONArray
193    ) -> collections.Sequence[user.UserThemes]:
194        return tuple(
195            user.UserThemes(
196                id=int(entry["userThemeId"]),
197                name=entry["userThemeName"] if "userThemeName" in entry else None,
198                description=entry["userThemeDescription"]
199                if "userThemeDescription" in entry
200                else None,
201            )
202            for entry in payload
203        )

Deserialize a raw JSON array of Bungie user themes.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of bungie user themes.
def deserialize_clan( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.clans.Clan:
254    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
255        current_user_map: collections.Mapping[str, clans.ClanMember] | None = None
256        if raw_current_user := payload.get("currentUserMemberMap"):
257            # This will get populated if only it was a GroupsV2.GroupResponse.
258            # GroupsV2.GetGroupsForMemberResponse doesn't have this field.
259            current_user_map = {
260                membership_type: self.deserialize_clan_member(membership)
261                for membership_type, membership in raw_current_user.items()
262            }
263
264        return self._deserialize_group_details(
265            data=payload["detail"],
266            clan_founder=self.deserialize_clan_member(payload["founder"]),
267            current_user_memberships=current_user_map,
268        )

Deserialize a raw JSON payload of Bungie clan information.

Parameters
Returns
def deserialize_clan_member( self, data: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.clans.ClanMember:
270    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
271        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
272        return clans.ClanMember(
273            net=self._net,
274            last_seen_name=destiny_user.last_seen_name,
275            id=destiny_user.id,
276            name=destiny_user.name,
277            icon=destiny_user.icon,
278            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
279            group_id=int(data["groupId"]),
280            joined_at=time.clean_date(data["joinDate"]),
281            types=destiny_user.types,
282            is_public=destiny_user.is_public,
283            type=destiny_user.type,
284            code=destiny_user.code,
285            is_online=data["isOnline"],
286            crossave_override=destiny_user.crossave_override,
287            bungie_user=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
288            if "bungieNetUserInfo" in data
289            else None,
290            member_type=enums.ClanMemberType(int(data["memberType"])),
291        )

Deserialize a JSON payload of a clan member information.

Parameters
Returns
def deserialize_clan_members( self, data: collections.abc.Mapping[str, typing.Any], /) -> Iterator[aiobungie.crates.clans.ClanMember]:
293    def deserialize_clan_members(
294        self, data: typedefs.JSONObject, /
295    ) -> iterators.Iterator[clans.ClanMember]:
296        return iterators.Iterator(
297            self.deserialize_clan_member(member) for member in data["results"]
298        )

Deserialize a JSON payload of a clan members information.

Parameters
Returns
def deserialize_group_member( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.clans.GroupMember:
300    def deserialize_group_member(
301        self, payload: typedefs.JSONObject
302    ) -> clans.GroupMember:
303        member = payload["member"]
304        return clans.GroupMember(
305            net=self._net,
306            join_date=time.clean_date(member["joinDate"]),
307            group_id=int(member["groupId"]),
308            member_type=enums.ClanMemberType(member["memberType"]),
309            is_online=member["isOnline"],
310            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
311            inactive_memberships=payload.get("areAllMembershipsInactive", None),
312            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
313            group=self._deserialize_group_details(payload["group"]),
314        )

Deserialize a JSON payload of group information for a member.

Parameters
Returns
def deserialize_clan_conversations( self, payload: collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
328    def deserialize_clan_conversations(
329        self, payload: typedefs.JSONArray
330    ) -> collections.Sequence[clans.ClanConversation]:
331        return tuple(self._deserialize_clan_conversation(conv) for conv in payload)

Deserialize a JSON array of a clan conversations information.

Parameters
Returns
def deserialize_app_owner( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.application.ApplicationOwner:
333    def deserialize_app_owner(
334        self, payload: typedefs.JSONObject
335    ) -> application.ApplicationOwner:
336        return application.ApplicationOwner(
337            net=self._net,
338            name=payload.get("bungieGlobalDisplayName"),
339            id=int(payload["membershipId"]),
340            type=enums.MembershipType(payload["membershipType"]),
341            icon=assets.Image(path=payload["iconPath"]),
342            is_public=payload["isPublic"],
343            code=payload.get("bungieGlobalDisplayNameCode", None),
344        )

Deserialize a JSON payload of Bungie Developer portal application owner information.

Parameters
Returns
  • aiobungie.crates.application.ApplicationOwner: An application owner.
def deserialize_app( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.application.Application:
346    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
347        return application.Application(
348            id=int(payload["applicationId"]),
349            name=payload["name"],
350            link=payload["link"],
351            status=payload["status"],
352            redirect_url=payload.get("redirectUrl", None),
353            created_at=time.clean_date(payload["creationDate"]),
354            published_at=time.clean_date(payload["firstPublished"]),
355            owner=self.deserialize_app_owner(payload["team"][0]["user"]),
356            scope=payload.get("scope"),
357        )

Deserialize a JSON payload of Bungie Developer portal application information.

Parameters
Returns
  • aiobungie.crates.application.Application: An application.
def deserialize_profile( self, payload: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.profile.Profile:
383    def deserialize_profile(self, payload: typedefs.JSONObject, /) -> profile.Profile:
384        payload = payload["data"]
385        id = int(payload["userInfo"]["membershipId"])
386        name = payload["userInfo"]["displayName"]
387        is_public = payload["userInfo"]["isPublic"]
388        type = enums.MembershipType(payload["userInfo"]["membershipType"])
389        last_played = time.clean_date(payload["dateLastPlayed"])
390        character_ids = tuple(int(cid) for cid in payload["characterIds"])
391        power_cap = payload["currentSeasonRewardPowerCap"]
392
393        return profile.Profile(
394            id=int(id),
395            name=name,
396            is_public=is_public,
397            type=type,
398            last_played=last_played,
399            character_ids=character_ids,
400            power_cap=power_cap,
401            net=self._net,
402        )

Deserialize a JSON payload of Bungie.net profile information.

Parameters
Returns
def deserialize_profile_item( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.profile.ProfileItemImpl:
404    def deserialize_profile_item(
405        self, payload: typedefs.JSONObject
406    ) -> profile.ProfileItemImpl:
407        instance_id: int | None = None
408        if raw_instance_id := payload.get("itemInstanceId"):
409            instance_id = int(raw_instance_id)
410
411        version_number: int | None = None
412        if raw_version := payload.get("versionNumber"):
413            version_number = int(raw_version)
414
415        transfer_status = enums.TransferStatus(payload["transferStatus"])
416
417        return profile.ProfileItemImpl(
418            net=self._net,
419            hash=payload["itemHash"],
420            quantity=payload["quantity"],
421            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
422            location=enums.ItemLocation(payload["location"]),
423            bucket=payload["bucketHash"],
424            transfer_status=transfer_status,
425            lockable=payload["lockable"],
426            state=enums.ItemState(payload["state"]),
427            dismantle_permissions=payload["dismantlePermission"],
428            is_wrapper=payload["isWrapper"],
429            instance_id=instance_id,
430            version_number=version_number,
431            ornament_id=payload.get("overrideStyleItemHash"),
432        )

Deserialize a JSON payload of a singular profile component item.

Parameters
Returns
def deserialize_objectives( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.records.Objective:
434    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
435        return records.Objective(
436            net=self._net,
437            hash=payload["objectiveHash"],
438            visible=payload["visible"],
439            complete=payload["complete"],
440            completion_value=payload["completionValue"],
441            progress=payload.get("progress"),
442            destination_hash=payload.get("destinationHash"),
443            activity_hash=payload.get("activityHash"),
444        )

Deserialize a JSON payload of an objective found in a record profile component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
  • aiobungie.crates.records.Objective: A record objective object.
def deserialize_records( self, payload: collections.abc.Mapping[str, typing.Any], scores: aiobungie.crates.records.RecordScores | None = None, **nodes: int) -> aiobungie.crates.records.Record:
447    def deserialize_records(
448        self,
449        payload: typedefs.JSONObject,
450        scores: records.RecordScores | None = None,
451        **nodes: int,
452    ) -> records.Record:
453        objectives: collections.Sequence[records.Objective] | None = None
454        interval_objectives: collections.Sequence[records.Objective] | None = None
455        record_state: records.RecordState | int
456
457        record_state = records.RecordState(payload["state"])
458
459        if raw_objs := payload.get("objectives"):
460            objectives = tuple(self.deserialize_objectives(obj) for obj in raw_objs)
461
462        if raw_interval_objs := payload.get("intervalObjectives"):
463            interval_objectives = tuple(
464                self.deserialize_objectives(obj) for obj in raw_interval_objs
465            )
466
467        return records.Record(
468            scores=scores,
469            categories_node_hash=nodes.get("categories_hash"),
470            seals_node_hash=nodes.get("seals_hash"),
471            state=record_state,
472            objectives=objectives,
473            interval_objectives=interval_objectives,
474            redeemed_count=payload.get("intervalsRedeemedCount", 0),
475            completion_times=payload.get("completedCount", None),
476            reward_visibility=payload.get("rewardVisibility"),
477        )

Deserialize a JSON object of a profile record component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
  • scores (records.RecordScores | None): The records scores object. This exists only to keep the signature of aiobungie.crates.CharacterRecord with the record object. As it will always be None in that object.
  • **nodes (int): An int kwargs use to grab the node hashes while deserializing components.
Returns
  • aiobungie.records.Record: A standard implementation of a profile record component.
def deserialize_character_records( self, payload: collections.abc.Mapping[str, typing.Any], scores: aiobungie.crates.records.RecordScores | None = None, record_hashes: collections.abc.Sequence[int] = ()) -> aiobungie.crates.records.CharacterRecord:
479    def deserialize_character_records(
480        self,
481        payload: typedefs.JSONObject,
482        scores: records.RecordScores | None = None,
483        record_hashes: collections.Sequence[int] = (),
484    ) -> records.CharacterRecord:
485        record = self.deserialize_records(payload, scores)
486        return records.CharacterRecord(
487            scores=scores,
488            categories_node_hash=record.categories_node_hash,
489            seals_node_hash=record.seals_node_hash,
490            state=record.state,
491            objectives=record.objectives,
492            interval_objectives=record.interval_objectives,
493            redeemed_count=payload.get("intervalsRedeemedCount", 0),
494            completion_times=payload.get("completedCount"),
495            reward_visibility=payload.get("rewardVisibility"),
496            record_hashes=record_hashes,
497        )

Deserialize a JSON object of a profile character record component.

This almost does the same this as deserialize_records but has more fields which can only be found in a character record.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
Returns
  • aiobungie.records.CharacterRecord: A standard implementation of a profile character record component.
def deserialize_character_dye( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.character.Dye:
499    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
500        return character.Dye(
501            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
502        )

Deserialize a JSON payload of a character's dye information.

Parameters
Returns
  • aiobungie.crates.character.Dye: Information about a character dye object.
def deserialize_character_customization( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.character.CustomizationOptions:
504    def deserialize_character_customization(
505        self, payload: typedefs.JSONObject
506    ) -> character.CustomizationOptions:
507        return character.CustomizationOptions(
508            personality=payload["personality"],
509            face=payload["face"],
510            skin_color=payload["skinColor"],
511            lip_color=payload["lipColor"],
512            eye_color=payload["eyeColor"],
513            hair_colors=payload.get("hairColors", ()),
514            feature_colors=payload.get("featureColors", ()),
515            decal_color=payload["decalColor"],
516            wear_helmet=payload["wearHelmet"],
517            hair_index=payload["hairIndex"],
518            feature_index=payload["featureIndex"],
519            decal_index=payload["decalIndex"],
520        )

Deserialize a JSON payload of a character customization information found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.CustomizationOptions: Information about a character customs object.
def deserialize_character_minimal_equipments( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.character.MinimalEquipments:
522    def deserialize_character_minimal_equipments(
523        self, payload: typedefs.JSONObject
524    ) -> character.MinimalEquipments:
525        if raw_dyes := payload.get("dyes"):
526            dyes = tuple(self.deserialize_character_dye(dye) for dye in raw_dyes)
527        else:
528            dyes = ()
529
530        return character.MinimalEquipments(
531            net=self._net, item_hash=payload["itemHash"], dyes=dyes
532        )

Deserialize a singular JSON peer view of equipment found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.MinimalEquipments: A minimal equipment object.
def deserialize_character_render_data( self, payload: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.character.RenderedData:
534    def deserialize_character_render_data(
535        self, payload: typedefs.JSONObject, /
536    ) -> character.RenderedData:
537        return character.RenderedData(
538            net=self._net,
539            customization=self.deserialize_character_customization(
540                payload["customization"]
541            ),
542            custom_dyes=tuple(
543                self.deserialize_character_dye(dye)
544                for dye in payload["customDyes"]
545                if dye
546            ),
547            equipment=tuple(
548                self.deserialize_character_minimal_equipments(equipment)
549                for equipment in payload["peerView"]["equipment"]
550            ),
551        )

Deserialize a JSON payload of a profile character render data component.

Parameters
Returns
def deserialize_available_activity( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.activity.AvailableActivity:
553    def deserialize_available_activity(
554        self, payload: typedefs.JSONObject
555    ) -> activity.AvailableActivity:
556        return activity.AvailableActivity(
557            hash=payload["activityHash"],
558            is_new=payload["isNew"],
559            is_completed=payload["isCompleted"],
560            is_visible=payload["isVisible"],
561            display_level=payload.get("displayLevel"),
562            recommended_light=payload.get("recommendedLight"),
563            difficulty=activity.Difficulty(payload["difficultyTier"]),
564            can_join=payload["canJoin"],
565            can_lead=payload["canLead"],
566        )

Deserialize a JSON payload of an available activities.

This method is used to deserialize an array of aiobungie.crates.CharacterActivity.available_activities.

Parameters
Returns
def deserialize_character_activity( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.activity.CharacterActivity:
568    def deserialize_character_activity(
569        self, payload: typedefs.JSONObject
570    ) -> activity.CharacterActivity:
571        current_mode: enums.GameMode | None = None
572        if raw_current_mode := payload.get("currentActivityModeType"):
573            current_mode = enums.GameMode(raw_current_mode)
574
575        if raw_current_modes := payload.get("currentActivityModeTypes"):
576            current_mode_types = tuple(
577                enums.GameMode(type_) for type_ in raw_current_modes
578            )
579        else:
580            current_mode_types = ()
581
582        return activity.CharacterActivity(
583            date_started=time.clean_date(payload["dateActivityStarted"]),
584            current_hash=payload["currentActivityHash"],
585            current_mode_hash=payload["currentActivityModeHash"],
586            current_mode=current_mode,
587            current_mode_hashes=payload.get("currentActivityModeHashes", ()),
588            current_mode_types=current_mode_types,
589            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
590            last_story_hash=payload["lastCompletedStoryHash"],
591            available_activities=tuple(
592                self.deserialize_available_activity(activity_)
593                for activity_ in payload["availableActivities"]
594            ),
595        )

Deserialize a JSON payload of character activity profile component.

Parameters
Returns
def deserialize_profile_items( self, payload: collections.abc.Mapping[str, typing.Any], /) -> collections.abc.Sequence[aiobungie.crates.profile.ProfileItemImpl]:
597    def deserialize_profile_items(
598        self, payload: typedefs.JSONObject, /
599    ) -> collections.Sequence[profile.ProfileItemImpl]:
600        return tuple(self.deserialize_profile_item(item) for item in payload["items"])

Deserialize a JSON payload of profile items component information.

This may deserialize profileInventories or profileCurrencies or any other alternatives.

Parameters
Returns
def deserialize_progressions( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.progressions.Progression:
643    def deserialize_progressions(
644        self, payload: typedefs.JSONObject
645    ) -> progressions.Progression:
646        return progressions.Progression(
647            hash=int(payload["progressionHash"]),
648            level=int(payload["level"]),
649            cap=int(payload["levelCap"]),
650            daily_limit=int(payload["dailyLimit"]),
651            weekly_limit=int(payload["weeklyLimit"]),
652            current_progress=int(payload["currentProgress"]),
653            daily_progress=int(payload["dailyProgress"]),
654            needed=int(payload["progressToNextLevel"]),
655            next_level=int(payload["nextLevelAt"]),
656        )
def deserialize_milestone( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.milestones.Milestone:
741    def deserialize_milestone(
742        self, payload: typedefs.JSONObject
743    ) -> milestones.Milestone:
744        start_date: datetime.datetime | None = None
745        if raw_start_date := payload.get("startDate"):
746            start_date = time.clean_date(raw_start_date)
747
748        end_date: datetime.datetime | None = None
749        if raw_end_date := payload.get("endDate"):
750            end_date = time.clean_date(raw_end_date)
751
752        rewards: collections.Collection[milestones.MilestoneReward] | None = None
753        if raw_rewards := payload.get("rewards"):
754            rewards = tuple(
755                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
756            )
757
758        activities: collections.Sequence[milestones.MilestoneActivity] | None = None
759        if raw_activities := payload.get("activities"):
760            activities = tuple(
761                self._deserialize_milestone_activity(active)
762                for active in raw_activities
763            )
764
765        quests: collections.Sequence[milestones.MilestoneQuest] | None = None
766        if raw_quests := payload.get("availableQuests"):
767            quests = tuple(
768                self._deserialize_milestone_available_quest(quest)
769                for quest in raw_quests
770            )
771
772        vendors: collections.Sequence[milestones.MilestoneVendor] | None = None
773        if raw_vendors := payload.get("vendors"):
774            vendors = tuple(
775                milestones.MilestoneVendor(
776                    vendor_hash=vendor["vendorHash"],
777                    preview_itemhash=vendor.get("previewItemHash"),
778                )
779                for vendor in raw_vendors
780            )
781
782        return milestones.Milestone(
783            hash=payload["milestoneHash"],
784            start_date=start_date,
785            end_date=end_date,
786            order=payload["order"],
787            rewards=rewards,
788            available_quests=quests,
789            activities=activities,
790            vendors=vendors,
791        )
def deserialize_characters( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.Character]:
808    def deserialize_characters(
809        self, payload: typedefs.JSONObject
810    ) -> collections.Mapping[int, character.Character]:
811        return {
812            int(char_id): self._set_character_attrs(char)
813            for char_id, char in payload["data"].items()
814        }
def deserialize_character( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.character.Character:
816    def deserialize_character(
817        self, payload: typedefs.JSONObject
818    ) -> character.Character:
819        return self._set_character_attrs(payload)
def deserialize_character_equipments( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Mapping[int, collections.abc.Sequence[aiobungie.crates.profile.ProfileItemImpl]]:
821    def deserialize_character_equipments(
822        self, payload: typedefs.JSONObject
823    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
824        return {
825            int(char_id): self.deserialize_profile_items(item)
826            for char_id, item in payload["data"].items()
827        }
def deserialize_character_activities( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.activity.CharacterActivity]:
829    def deserialize_character_activities(
830        self, payload: typedefs.JSONObject
831    ) -> collections.Mapping[int, activity.CharacterActivity]:
832        return {
833            int(char_id): self.deserialize_character_activity(data)
834            for char_id, data in payload["data"].items()
835        }
def deserialize_characters_render_data( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.RenderedData]:
837    def deserialize_characters_render_data(
838        self, payload: typedefs.JSONObject
839    ) -> collections.Mapping[int, character.RenderedData]:
840        return {
841            int(char_id): self.deserialize_character_render_data(data)
842            for char_id, data in payload["data"].items()
843        }
def deserialize_character_progressions( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.character.CharacterProgression:
845    def deserialize_character_progressions(
846        self, payload: typedefs.JSONObject
847    ) -> character.CharacterProgression:
848        progressions_ = {
849            int(prog_id): self.deserialize_progressions(prog)
850            for prog_id, prog in payload["progressions"].items()
851        }
852
853        factions = {
854            int(faction_id): self._deserialize_factions(faction)
855            for faction_id, faction in payload["factions"].items()
856        }
857
858        milestones_ = {
859            int(milestone_hash): self.deserialize_milestone(milestone)
860            for milestone_hash, milestone in payload["milestones"].items()
861        }
862
863        uninstanced_item_objectives = {
864            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
865            for item_hash, obj in payload["uninstancedItemObjectives"].items()
866        }
867
868        artifact = payload["seasonalArtifact"]
869        seasonal_artifact = season.CharacterScopedArtifact(
870            hash=artifact["artifactHash"],
871            points_used=artifact["pointsUsed"],
872            reset_count=artifact["resetCount"],
873            tiers=tuple(
874                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
875            ),
876        )
877        checklists = payload["checklists"]
878
879        return character.CharacterProgression(
880            progressions=progressions_,
881            factions=factions,
882            checklists=checklists,
883            milestones=milestones_,
884            seasonal_artifact=seasonal_artifact,
885            uninstanced_item_objectives=uninstanced_item_objectives,
886        )
def deserialize_character_progressions_mapping( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.CharacterProgression]:
889    def deserialize_character_progressions_mapping(self, payload: typedefs.JSONObject) -> collections.Mapping[int, character.CharacterProgression]:
890        character_progressions: collections.MutableMapping[int, character.CharacterProgression] = {}
891        for char_id, data in payload["data"].items():
892            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)
893        return character_progressions
def deserialize_characters_records( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.CharacterRecord]:
896    def deserialize_characters_records(
897        self,
898        payload: typedefs.JSONObject,
899    ) -> collections.Mapping[int, records.CharacterRecord]:
900        return {
901            int(rec_id): self.deserialize_character_records(
902                rec, record_hashes=payload.get("featuredRecordHashes", ())
903            )
904            for rec_id, rec in payload["records"].items()
905        }
def deserialize_profile_records( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.Record]:
907    def deserialize_profile_records(
908        self, payload: typedefs.JSONObject
909    ) -> collections.Mapping[int, records.Record]:
910        raw_profile_records = payload["data"]
911        scores = records.RecordScores(
912            current_score=raw_profile_records["score"],
913            legacy_score=raw_profile_records["legacyScore"],
914            lifetime_score=raw_profile_records["lifetimeScore"],
915        )
916        return {
917            int(record_id): self.deserialize_records(
918                record,
919                scores,
920                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
921                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
922            )
923            for record_id, record in raw_profile_records["records"].items()
924        }
def deserialize_craftables_component( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.components.CraftablesComponent:
960    def deserialize_craftables_component(
961        self, payload: typedefs.JSONObject
962    ) -> components.CraftablesComponent:
963        return components.CraftablesComponent(
964            net=self._net,
965            craftables={
966                int(item_id): self._deserialize_craftable_item(item)
967                for item_id, item in payload["craftables"].items()
968                if item is not None
969            },
970            crafting_root_node_hash=payload["craftingRootNodeHash"],
971        )
def deserialize_components( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.components.Component:
 973    def deserialize_components(  # noqa: C901 Too complex.
 974        self, payload: typedefs.JSONObject
 975    ) -> components.Component:
 976        # Due to how complex this method is, We'll stick to
 977        # typing.Optional here.
 978
 979        profile_: profile.Profile | None = None
 980        if raw_profile := payload.get("profile"):
 981            profile_ = self.deserialize_profile(raw_profile)
 982
 983        profile_progression: profile.ProfileProgression | None = None
 984        if raw_profile_progression := payload.get("profileProgression"):
 985            profile_progression = self.deserialize_profile_progression(
 986                raw_profile_progression
 987            )
 988
 989        profile_currencies: typing.Optional[
 990            collections.Sequence[profile.ProfileItemImpl]
 991        ] = None
 992        if raw_profile_currencies := payload.get("profileCurrencies"):
 993            if "data" in raw_profile_currencies:
 994                profile_currencies = self.deserialize_profile_items(
 995                    raw_profile_currencies["data"]
 996                )
 997
 998        profile_inventories: typing.Optional[
 999            collections.Sequence[profile.ProfileItemImpl]
1000        ] = None
1001        if raw_profile_inventories := payload.get("profileInventory"):
1002            if "data" in raw_profile_inventories:
1003                profile_inventories = self.deserialize_profile_items(
1004                    raw_profile_inventories["data"]
1005                )
1006
1007        profile_records: typing.Optional[collections.Mapping[int, records.Record]] = (
1008            None
1009        )
1010
1011        if raw_profile_records_ := payload.get("profileRecords"):
1012            profile_records = self.deserialize_profile_records(raw_profile_records_)
1013
1014        characters: typing.Optional[collections.Mapping[int, character.Character]] = (
1015            None
1016        )
1017        if raw_characters := payload.get("characters"):
1018            characters = self.deserialize_characters(raw_characters)
1019
1020        character_records: typing.Optional[
1021            collections.Mapping[int, records.CharacterRecord]
1022        ] = None
1023
1024        if raw_character_records := payload.get("characterRecords"):
1025            # Had to do it in two steps..
1026            to_update = {}
1027            for _, data in raw_character_records["data"].items():
1028                for record_id, record in data.items():
1029                    to_update[record_id] = record
1030
1031            character_records = {
1032                int(rec_id): self.deserialize_character_records(
1033                    rec, record_hashes=to_update.get("featuredRecordHashes", ())
1034                )
1035                for rec_id, rec in to_update["records"].items()
1036            }
1037
1038        character_equipments: typing.Optional[
1039            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1040        ] = None
1041        if raw_character_equips := payload.get("characterEquipment"):
1042            character_equipments = self.deserialize_character_equipments(
1043                raw_character_equips
1044            )
1045
1046        character_inventories: typing.Optional[
1047            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1048        ] = None
1049        if raw_character_inventories := payload.get("characterInventories"):
1050            if "data" in raw_character_inventories:
1051                character_inventories = self.deserialize_character_equipments(
1052                    raw_character_inventories
1053                )
1054
1055        character_activities: typing.Optional[
1056            collections.Mapping[int, activity.CharacterActivity]
1057        ] = None
1058        if raw_char_acts := payload.get("characterActivities"):
1059            character_activities = self.deserialize_character_activities(raw_char_acts)
1060
1061        character_render_data: typing.Optional[
1062            collections.Mapping[int, character.RenderedData]
1063        ] = None
1064        if raw_character_render_data := payload.get("characterRenderData"):
1065            character_render_data = self.deserialize_characters_render_data(
1066                raw_character_render_data
1067            )
1068
1069        character_progressions: typing.Optional[
1070            collections.Mapping[int, character.CharacterProgression]
1071        ] = None
1072
1073        if raw_character_progressions := payload.get("characterProgressions"):
1074            character_progressions = self.deserialize_character_progressions_mapping(
1075                raw_character_progressions
1076            )
1077
1078        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1079        if raw_profile_string_vars := payload.get("profileStringVariables"):
1080            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1081
1082        character_string_vars: typing.Optional[
1083            collections.Mapping[int, collections.Mapping[int, int]]
1084        ] = None
1085        if raw_character_string_vars := payload.get("characterStringVariables"):
1086            character_string_vars = {
1087                int(char_id): data["integerValuesByHash"]
1088                for char_id, data in raw_character_string_vars["data"].items()
1089            }
1090
1091        metrics: typing.Optional[
1092            collections.Sequence[
1093                collections.Mapping[int, tuple[bool, records.Objective | None]]
1094            ]
1095        ] = None
1096        root_node_hash: int | None = None
1097
1098        if raw_metrics := payload.get("metrics"):
1099            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1100            metrics = tuple(
1101                {
1102                    int(metrics_hash): (
1103                        data["invisible"],
1104                        self.deserialize_objectives(data["objectiveProgress"])
1105                        if "objectiveProgress" in data
1106                        else None,
1107                    )
1108                }
1109                for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1110            )
1111        transitory: fireteams.FireteamParty | None = None
1112        if raw_transitory := payload.get("profileTransitoryData"):
1113            if "data" in raw_transitory:
1114                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1115
1116        item_components: components.ItemsComponent | None = None
1117        if raw_item_components := payload.get("itemComponents"):
1118            item_components = self.deserialize_items_component(raw_item_components)
1119
1120        profile_plugsets: typing.Optional[
1121            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1122        ] = None
1123
1124        if raw_profile_plugs := payload.get("profilePlugSets"):
1125            profile_plugsets = {
1126                int(index): [self.deserialize_plug_item_state(state) for state in data]
1127                for index, data in raw_profile_plugs["data"]["plugs"].items()
1128            }
1129
1130        character_plugsets: typing.Optional[
1131            collections.Mapping[
1132                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1133            ]
1134        ] = None
1135        if raw_char_plugsets := payload.get("characterPlugSets"):
1136            character_plugsets = {
1137                int(char_id): {
1138                    int(index): [
1139                        self.deserialize_plug_item_state(state) for state in data
1140                    ]
1141                    for index, data in inner["plugs"].items()
1142                }
1143                for char_id, inner in raw_char_plugsets["data"].items()
1144            }
1145
1146        character_collectibles: typing.Optional[
1147            collections.Mapping[int, items.Collectible]
1148        ] = None
1149        if raw_character_collectibles := payload.get("characterCollectibles"):
1150            character_collectibles = {
1151                int(char_id): self._deserialize_collectible(data)
1152                for char_id, data in raw_character_collectibles["data"].items()
1153            }
1154
1155        profile_collectibles: items.Collectible | None = None
1156        if raw_profile_collectibles := payload.get("profileCollectibles"):
1157            profile_collectibles = self._deserialize_collectible(
1158                raw_profile_collectibles["data"]
1159            )
1160
1161        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1162        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1163            profile_nodes = {
1164                int(node_hash): self._deserialize_node(node)
1165                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1166            }
1167
1168        character_nodes: typing.Optional[
1169            collections.Mapping[int, collections.Mapping[int, records.Node]]
1170        ] = None
1171        if raw_character_nodes := payload.get("characterPresentationNodes"):
1172            character_nodes = {
1173                int(char_id): {
1174                    int(node_hash): self._deserialize_node(node)
1175                    for node_hash, node in each_character["nodes"].items()
1176                }
1177                for char_id, each_character in raw_character_nodes["data"].items()
1178            }
1179
1180        platform_silver: typing.Optional[
1181            collections.Mapping[str, profile.ProfileItemImpl]
1182        ] = None
1183        if raw_platform_silver := payload.get("platformSilver"):
1184            if "data" in raw_platform_silver:
1185                platform_silver = {
1186                    platform_name: self.deserialize_profile_item(item)
1187                    for platform_name, item in raw_platform_silver["data"][
1188                        "platformSilver"
1189                    ].items()
1190                }
1191
1192        character_currency_lookups: typing.Optional[
1193            collections.Mapping[int, collections.Sequence[items.Currency]]
1194        ] = None
1195        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1196            if "data" in raw_char_lookups:
1197                character_currency_lookups = {
1198                    int(char_id): self._deserialize_currencies(currency)
1199                    for char_id, currency in raw_char_lookups["data"].items()
1200                }
1201
1202        character_craftables: typing.Optional[
1203            collections.Mapping[int, components.CraftablesComponent]
1204        ] = None
1205        if raw_character_craftables := payload.get("characterCraftables"):
1206            if "data" in raw_character_craftables:
1207                character_craftables = {
1208                    int(char_id): self.deserialize_craftables_component(craftable)
1209                    for char_id, craftable in raw_character_craftables["data"].items()
1210                }
1211
1212        return components.Component(
1213            profiles=profile_,
1214            profile_progression=profile_progression,
1215            profile_currencies=profile_currencies,
1216            profile_inventories=profile_inventories,
1217            profile_records=profile_records,
1218            characters=characters,
1219            character_records=character_records,
1220            character_equipments=character_equipments,
1221            character_inventories=character_inventories,
1222            character_activities=character_activities,
1223            character_render_data=character_render_data,
1224            character_progressions=character_progressions,
1225            profile_string_variables=profile_string_vars,
1226            character_string_variables=character_string_vars,
1227            metrics=metrics,
1228            root_node_hash=root_node_hash,
1229            transitory=transitory,
1230            item_components=item_components,
1231            profile_plugsets=profile_plugsets,
1232            character_plugsets=character_plugsets,
1233            character_collectibles=character_collectibles,
1234            profile_collectibles=profile_collectibles,
1235            profile_nodes=profile_nodes,
1236            character_nodes=character_nodes,
1237            platform_silver=platform_silver,
1238            character_currency_lookups=character_currency_lookups,
1239            character_craftables=character_craftables,
1240        )

Deserialize a JSON payload of Bungie.net profile components information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_items_component( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.components.ItemsComponent:
1242    def deserialize_items_component(
1243        self, payload: typedefs.JSONObject
1244    ) -> components.ItemsComponent:
1245        # Due to how complex this method is, We'll stick to typing.Optional.
1246        instances: typing.Optional[
1247            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1248        ] = None
1249        if raw_instances := payload.get("instances"):
1250            instances = tuple(
1251                {int(ins_id): self.deserialize_instanced_item(item)}
1252                for ins_id, item in raw_instances["data"].items()
1253            )
1254
1255        render_data: typing.Optional[
1256            collections.Mapping[int, tuple[bool, dict[int, int]]]
1257        ] = None
1258        if raw_render_data := payload.get("renderData"):
1259            render_data = {
1260                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1261                for ins_id, data in raw_render_data["data"].items()
1262            }
1263
1264        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1265        if raw_stats := payload.get("stats"):
1266            stats = {}
1267            for ins_id, stat in raw_stats["data"].items():
1268                for _, items_ in stat.items():
1269                    stats[int(ins_id)] = self.deserialize_item_stats_view(items_)
1270
1271        sockets: typing.Optional[
1272            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1273        ] = None
1274        if raw_sockets := payload.get("sockets"):
1275            sockets = {
1276                int(ins_id): tuple(
1277                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1278                )
1279                for ins_id, item in raw_sockets["data"].items()
1280            }
1281
1282        objectives: typing.Optional[
1283            collections.Mapping[int, collections.Sequence[records.Objective]]
1284        ] = None
1285        if raw_objectives := payload.get("objectives"):
1286            objectives = {
1287                int(ins_id): tuple(
1288                    self.deserialize_objectives(objective)
1289                    for objective in data["objectives"]
1290                )
1291                for ins_id, data in raw_objectives["data"].items()
1292            }
1293
1294        perks: typing.Optional[
1295            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1296        ] = None
1297        if raw_perks := payload.get("perks"):
1298            perks = {
1299                int(ins_id): tuple(
1300                    self.deserialize_item_perk(perk) for perk in item["perks"]
1301                )
1302                for ins_id, item in raw_perks["data"].items()
1303            }
1304
1305        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1306        if raw_plug_states := payload.get("plugStates"):
1307            plug_states = tuple(
1308                self.deserialize_plug_item_state(plug)
1309                for _, plug in raw_plug_states["data"].items()
1310            )
1311
1312        reusable_plugs: typing.Optional[
1313            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1314        ] = None
1315        if raw_re_plugs := payload.get("reusablePlugs"):
1316            reusable_plugs = {
1317                int(ins_id): tuple(
1318                    self.deserialize_plug_item_state(state) for state in inner
1319                )
1320                for ins_id, plug in raw_re_plugs["data"].items()
1321                for inner in tuple(plug["plugs"].values())
1322            }
1323
1324        plug_objectives: typing.Optional[
1325            collections.Mapping[
1326                int, collections.Mapping[int, collections.Collection[records.Objective]]
1327            ]
1328        ] = None
1329        if raw_plug_objectives := payload.get("plugObjectives"):
1330            plug_objectives = {
1331                int(ins_id): {
1332                    int(obj_hash): tuple(
1333                        self.deserialize_objectives(obj) for obj in objs
1334                    )
1335                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1336                }
1337                for ins_id, inner in raw_plug_objectives["data"].items()
1338            }
1339
1340        return components.ItemsComponent(
1341            sockets=sockets,
1342            stats=stats,
1343            render_data=render_data,
1344            instances=instances,
1345            objectives=objectives,
1346            perks=perks,
1347            plug_states=plug_states,
1348            reusable_plugs=reusable_plugs,
1349            plug_objectives=plug_objectives,
1350        )

Deserialize a JSON objects within the itemComponents key.`

def deserialize_character_component( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.components.CharacterComponent:
1352    def deserialize_character_component(
1353        self, payload: typedefs.JSONObject
1354    ) -> components.CharacterComponent:
1355        character_: character.Character | None = None
1356        if raw_singular_character := payload.get("character"):
1357            character_ = self.deserialize_character(raw_singular_character["data"])
1358
1359        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1360        if raw_inventory := payload.get("inventory"):
1361            if "data" in raw_inventory:
1362                inventory = self.deserialize_profile_items(raw_inventory["data"])
1363
1364        activities: activity.CharacterActivity | None = None
1365        if raw_activities := payload.get("activities"):
1366            activities = self.deserialize_character_activity(raw_activities["data"])
1367
1368        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1369        if raw_equipments := payload.get("equipment"):
1370            equipment = self.deserialize_profile_items(raw_equipments["data"])
1371
1372        progressions_: character.CharacterProgression | None = None
1373        if raw_progressions := payload.get("progressions"):
1374            progressions_ = self.deserialize_character_progressions(
1375                raw_progressions["data"]
1376            )
1377
1378        render_data: character.RenderedData | None = None
1379        if raw_render_data := payload.get("renderData"):
1380            render_data = self.deserialize_character_render_data(
1381                raw_render_data["data"]
1382            )
1383
1384        character_records: typing.Optional[
1385            collections.Mapping[int, records.CharacterRecord]
1386        ] = None
1387        if raw_char_records := payload.get("records"):
1388            character_records = self.deserialize_characters_records(
1389                raw_char_records["data"]
1390            )
1391
1392        item_components: components.ItemsComponent | None = None
1393        if raw_item_components := payload.get("itemComponents"):
1394            item_components = self.deserialize_items_component(raw_item_components)
1395
1396        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1397        if raw_nodes := payload.get("presentationNodes"):
1398            nodes = {
1399                int(node_hash): self._deserialize_node(node)
1400                for node_hash, node in raw_nodes["data"]["nodes"].items()
1401            }
1402
1403        collectibles: items.Collectible | None = None
1404        if raw_collectibles := payload.get("collectibles"):
1405            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1406
1407        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1408        if raw_currencies := payload.get("currencyLookups"):
1409            if "data" in raw_currencies:
1410                currency_lookups = self._deserialize_currencies(raw_currencies)
1411
1412        return components.CharacterComponent(
1413            activities=activities,
1414            equipment=equipment,
1415            inventory=inventory,
1416            progressions=progressions_,
1417            render_data=render_data,
1418            character=character_,
1419            character_records=character_records,
1420            profile_records=None,
1421            item_components=item_components,
1422            currency_lookups=currency_lookups,
1423            collectibles=collectibles,
1424            nodes=nodes,
1425        )

Deserialize a JSON payload of Destiny 2 character component.

Parameters
Returns
def deserialize_inventory_results( self, payload: collections.abc.Mapping[str, typing.Any]) -> Iterator[aiobungie.crates.entity.SearchableEntity]:
1444    def deserialize_inventory_results(
1445        self, payload: typedefs.JSONObject
1446    ) -> iterators.Iterator[entity.SearchableEntity]:
1447        return iterators.Iterator(
1448            [
1449                entity.SearchableEntity(
1450                    net=self._net,
1451                    hash=data["hash"],
1452                    entity_type=data["entityType"],
1453                    weight=data["weight"],
1454                    suggested_words=payload["suggestedWords"],
1455                    name=data["displayProperties"]["name"],
1456                    has_icon=data["displayProperties"]["hasIcon"],
1457                    description=typedefs.unknown(
1458                        data["displayProperties"]["description"]
1459                    ),
1460                    icon=assets.Image(path=data["displayProperties"]["icon"]),
1461                )
1462                for data in payload["results"]["results"]
1463            ]
1464        )

Deserialize results of searched Destiny2 entities.

Parameters
Returns
def deserialize_inventory_entity( self, payload: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.entity.InventoryEntity:
1493    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1494        self, payload: typedefs.JSONObject, /
1495    ) -> entity.InventoryEntity:
1496        props = self._set_entity_attrs(payload)
1497        objects = self._deserialize_inventory_item_objects(payload)
1498
1499        collectible_hash: int | None = None
1500        if raw_collectible_hash := payload.get("collectibleHash"):
1501            collectible_hash = int(raw_collectible_hash)
1502
1503        secondary_icon: assets.Image | None = None
1504        if raw_second_icon := payload.get("secondaryIcon"):
1505            secondary_icon = assets.Image(path=raw_second_icon)
1506
1507        secondary_overlay: assets.Image | None = None
1508        if raw_second_overlay := payload.get("secondaryOverlay"):
1509            secondary_overlay = assets.Image(path=raw_second_overlay)
1510
1511        secondary_special: assets.Image | None = None
1512        if raw_second_special := payload.get("secondarySpecial"):
1513            secondary_special = assets.Image(path=raw_second_special)
1514
1515        screenshot: assets.Image | None = None
1516        if raw_screenshot := payload.get("screenshot"):
1517            screenshot = assets.Image(path=raw_screenshot)
1518
1519        watermark_icon: assets.Image | None = None
1520        if raw_watermark_icon := payload.get("iconWatermark"):
1521            watermark_icon = assets.Image(path=raw_watermark_icon)
1522
1523        watermark_shelved: assets.Image | None = None
1524        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1525            watermark_shelved = assets.Image(path=raw_watermark_shelved)
1526
1527        about: str | None = None
1528        if raw_about := payload.get("flavorText"):
1529            about = raw_about
1530
1531        ui_item_style: str | None = None
1532        if raw_ui_style := payload.get("uiItemDisplayStyle"):
1533            ui_item_style = raw_ui_style
1534
1535        tier_and_name: str | None = None
1536        if raw_tier_and_name := payload.get("itemTypeAndTierDisplayName"):
1537            tier_and_name = raw_tier_and_name
1538
1539        type_name: str | None = None
1540        if raw_type_name := payload.get("itemTypeDisplayName"):
1541            type_name = raw_type_name
1542
1543        display_source: str | None = None
1544        if raw_display_source := payload.get("displaySource"):
1545            display_source = raw_display_source
1546
1547        lorehash: int | None = None
1548        if raw_lore_hash := payload.get("loreHash"):
1549            lorehash = int(raw_lore_hash)
1550
1551        summary_hash: int | None = None
1552        if raw_summary_hash := payload.get("summaryItemHash"):
1553            summary_hash = raw_summary_hash
1554
1555        breaker_type_hash: int | None = None
1556        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1557            breaker_type_hash = int(raw_breaker_type_hash)
1558
1559        damage_types: typing.Optional[collections.Sequence[int]] = None
1560        if raw_damage_types := payload.get("damageTypes"):
1561            damage_types = tuple(int(type_) for type_ in raw_damage_types)
1562
1563        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1564        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1565            damagetype_hashes = tuple(int(type_) for type_ in raw_damagetype_hashes)
1566
1567        default_damagetype_hash: int | None = None
1568        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1569            default_damagetype_hash = int(raw_defaultdmg_hash)
1570
1571        emblem_objective_hash: int | None = None
1572        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1573            emblem_objective_hash = int(raw_emblem_obj_hash)
1574
1575        tier_type: enums.TierType | None = None
1576        tier: enums.ItemTier | None = None
1577        bucket_hash: int | None = None
1578        recovery_hash: int | None = None
1579        tier_name: str | None = None
1580        isinstance_item: bool = False
1581        expire_tool_tip: str | None = None
1582        expire_in_orbit_message: str | None = None
1583        suppress_expiration: bool = False
1584        max_stack_size: int | None = None
1585        stack_label: str | None = None
1586
1587        if inventory := payload.get("inventory"):
1588            tier_type = enums.TierType(int(inventory["tierType"]))
1589            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1590            bucket_hash = int(inventory["bucketTypeHash"])
1591            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1592            tier_name = inventory["tierTypeName"]
1593            isinstance_item = inventory["isInstanceItem"]
1594            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1595            max_stack_size = int(inventory["maxStackSize"])
1596
1597            try:
1598                stack_label = inventory["stackUniqueLabel"]
1599            except KeyError:
1600                pass
1601
1602        if "traitHashes" in payload:
1603            trait_hashes = tuple(
1604                int(trait_hash) for trait_hash in payload["traitHashes"]
1605            )
1606        else:
1607            trait_hashes = ()
1608
1609        if "traitIds" in payload:
1610            trait_ids = tuple(trait_id for trait_id in payload["traitIds"])
1611        else:
1612            trait_ids = ()
1613
1614        return entity.InventoryEntity(
1615            net=self._net,
1616            collectible_hash=collectible_hash,
1617            name=props.name,
1618            about=about,
1619            emblem_objective_hash=emblem_objective_hash,
1620            suppress_expiration=suppress_expiration,
1621            max_stack_size=max_stack_size,
1622            stack_label=stack_label,
1623            tier=tier,
1624            tier_type=tier_type,
1625            tier_name=tier_name,
1626            bucket_hash=bucket_hash,
1627            recovery_bucket_hash=recovery_hash,
1628            isinstance_item=isinstance_item,
1629            expire_in_orbit_message=expire_in_orbit_message,
1630            expiration_tooltip=expire_tool_tip,
1631            lore_hash=lorehash,
1632            type_and_tier_name=tier_and_name,
1633            summary_hash=summary_hash,
1634            ui_display_style=ui_item_style,
1635            type_name=type_name,
1636            breaker_type_hash=breaker_type_hash,
1637            description=props.description,
1638            display_source=display_source,
1639            hash=props.hash,
1640            damage_types=damage_types,
1641            index=props.index,
1642            icon=props.icon,
1643            has_icon=props.has_icon,
1644            screenshot=screenshot,
1645            watermark_icon=watermark_icon,
1646            watermark_shelved=watermark_shelved,
1647            secondary_icon=secondary_icon,
1648            secondary_overlay=secondary_overlay,
1649            secondary_special=secondary_special,
1650            type=enums.ItemType(int(payload["itemType"])),
1651            category_hashes=tuple(
1652                int(hash_) for hash_ in payload["itemCategoryHashes"]
1653            ),
1654            item_class=enums.Class(int(payload["classType"])),
1655            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1656            breaker_type=int(payload["breakerType"]),
1657            default_damagetype=int(payload["defaultDamageType"]),
1658            default_damagetype_hash=default_damagetype_hash,
1659            damagetype_hashes=damagetype_hashes,
1660            tooltip_notifications=payload["tooltipNotifications"],
1661            not_transferable=payload["nonTransferrable"],
1662            allow_actions=payload["allowActions"],
1663            is_equippable=payload["equippable"],
1664            objects=objects,
1665            background_colors=payload.get("backgroundColor", {}),
1666            season_hash=payload.get("seasonHash"),
1667            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1668            trait_hashes=trait_hashes,
1669            trait_ids=trait_ids,
1670        )

Deserialize a JSON payload of an inventory entity item information.

This can be any item from DestinyInventoryItemDefinition definition.

Parameters
Returns
def deserialize_objective_entity( self, payload: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.entity.ObjectiveEntity:
1672    def deserialize_objective_entity(
1673        self, payload: typedefs.JSONObject, /
1674    ) -> entity.ObjectiveEntity:
1675        props = self._set_entity_attrs(payload)
1676        return entity.ObjectiveEntity(
1677            net=self._net,
1678            hash=props.hash,
1679            index=props.index,
1680            description=props.description,
1681            name=props.name,
1682            has_icon=props.has_icon,
1683            icon=props.icon,
1684            unlock_value_hash=payload["unlockValueHash"],
1685            completion_value=payload["completionValue"],
1686            scope=entity.GatingScope(int(payload["scope"])),
1687            location_hash=payload["locationHash"],
1688            allowed_negative_value=payload["allowNegativeValue"],
1689            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1690            counting_downward=payload["isCountingDownward"],
1691            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1692            progress_description=payload["progressDescription"],
1693            perks=payload["perks"],
1694            stats=payload["stats"],
1695            minimum_visibility=payload["minimumVisibilityThreshold"],
1696            allow_over_completion=payload["allowOvercompletion"],
1697            show_value_style=payload["showValueOnComplete"],
1698            display_only_objective=payload["isDisplayOnlyObjective"],
1699            complete_value_style=entity.ValueUIStyle(
1700                int(payload["completedValueStyle"])
1701            ),
1702            progress_value_style=entity.ValueUIStyle(
1703                int(payload["inProgressValueStyle"])
1704            ),
1705            ui_label=payload["uiLabel"],
1706            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1707        )

Deserialize a JSON payload of an objective entity information.

Parameters
Returns
def deserialize_activity( self, payload: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.activity.Activity:
1735    def deserialize_activity(
1736        self,
1737        payload: typedefs.JSONObject,
1738        /,
1739    ) -> activity.Activity:
1740        period = time.clean_date(payload["period"])
1741        details = payload["activityDetails"]
1742        ref_id = int(details["referenceId"])
1743        instance_id = int(details["instanceId"])
1744        mode = enums.GameMode(details["mode"])
1745        modes = tuple(enums.GameMode(int(mode_)) for mode_ in details["modes"])
1746        is_private = details["isPrivate"]
1747        membership_type = enums.MembershipType(int(details["membershipType"]))
1748
1749        # Since we're using the same fields for post activity method
1750        # this check is required since post activity doesn't values values
1751        values = self._deserialize_activity_values(payload["values"])
1752
1753        return activity.Activity(
1754            net=self._net,
1755            hash=ref_id,
1756            instance_id=instance_id,
1757            mode=mode,
1758            modes=modes,
1759            is_private=is_private,
1760            membership_type=membership_type,
1761            occurred_at=period,
1762            values=values,
1763        )

Deserialize a JSON payload of an activity history information.

Parameters
Returns
def deserialize_activities( self, payload: collections.abc.Mapping[str, typing.Any]) -> Iterator[aiobungie.crates.activity.Activity]:
1765    def deserialize_activities(
1766        self, payload: typedefs.JSONObject
1767    ) -> iterators.Iterator[activity.Activity]:
1768        return iterators.Iterator(
1769            [
1770                self.deserialize_activity(activity_)
1771                for activity_ in payload["activities"]
1772            ]
1773        )

Deserialize a JSON payload of an array of activity history information.

Parameters
Returns
def deserialize_extended_weapon_values( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.activity.ExtendedWeaponValues:
1775    def deserialize_extended_weapon_values(
1776        self, payload: typedefs.JSONObject
1777    ) -> activity.ExtendedWeaponValues:
1778        assists: int | None = None
1779        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1780            assists = raw_assists["basic"]["value"]
1781        assists_damage: int | None = None
1782
1783        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1784            assists_damage = raw_assists_damage["basic"]["value"]
1785
1786        return activity.ExtendedWeaponValues(
1787            reference_id=int(payload["referenceId"]),
1788            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1789            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1790                "value"
1791            ],
1792            assists=assists,
1793            assists_damage=assists_damage,
1794            precision_kills_percentage=(
1795                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1796                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1797                    "displayValue"
1798                ],
1799            ),
1800        )

Deserialize values of extended weapons JSON object.

Parameters
Returns
def deserialize_post_activity_player( self, payload: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.activity.PostActivityPlayer:
1821    def deserialize_post_activity_player(
1822        self, payload: typedefs.JSONObject, /
1823    ) -> activity.PostActivityPlayer:
1824        player = payload["player"]
1825
1826        class_hash: int | None = None
1827        if (class_hash := player.get("classHash")) is not None:
1828            class_hash = class_hash
1829
1830        race_hash: int | None = None
1831        if (race_hash := player.get("raceHash")) is not None:
1832            race_hash = race_hash
1833
1834        gender_hash: int | None = None
1835        if (gender_hash := player.get("genderHash")) is not None:
1836            gender_hash = gender_hash
1837
1838        character_class: str | None = None
1839        if character_class := player.get("characterClass"):
1840            character_class = character_class
1841
1842        character_level: int | None = None
1843        if (character_level := player.get("characterLevel")) is not None:
1844            character_level = character_level
1845
1846        return activity.PostActivityPlayer(
1847            standing=int(payload["standing"]),
1848            score=int(payload["score"]["basic"]["value"]),
1849            character_id=payload["characterId"],
1850            destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]),
1851            character_class=character_class,
1852            character_level=character_level,
1853            race_hash=race_hash,
1854            gender_hash=gender_hash,
1855            class_hash=class_hash,
1856            light_level=int(player["lightLevel"]),
1857            emblem_hash=int(player["emblemHash"]),
1858            values=self._deserialize_activity_values(payload["values"]),
1859            extended_values=self._deserialize_extended_values(payload["extended"]),
1860        )

Deserialize a JSON payload of a post activity player information.

Parameters
Returns
def deserialize_post_activity( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.activity.PostActivity:
1872    def deserialize_post_activity(
1873        self, payload: typedefs.JSONObject
1874    ) -> activity.PostActivity:
1875        period = time.clean_date(payload["period"])
1876        details = payload["activityDetails"]
1877        ref_id = int(details["referenceId"])
1878        instance_id = int(details["instanceId"])
1879        mode = enums.GameMode(details["mode"])
1880        modes = tuple(enums.GameMode(int(mode_)) for mode_ in details["modes"])
1881        is_private = details["isPrivate"]
1882        membership_type = enums.MembershipType(int(details["membershipType"]))
1883        return activity.PostActivity(
1884            net=self._net,
1885            hash=ref_id,
1886            membership_type=membership_type,
1887            instance_id=instance_id,
1888            mode=mode,
1889            modes=modes,
1890            is_private=is_private,
1891            occurred_at=period,
1892            starting_phase=int(payload["startingPhaseIndex"]),
1893            players=tuple(
1894                self.deserialize_post_activity_player(player)
1895                for player in payload["entries"]
1896            ),
1897            teams=tuple(
1898                self._deserialize_post_activity_team(team) for team in payload["teams"]
1899            ),
1900        )

Deserialize a JSON payload of a post activity information.

Parameters
Returns
def deserialize_aggregated_activity( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.activity.AggregatedActivity:
1938    def deserialize_aggregated_activity(
1939        self, payload: typedefs.JSONObject
1940    ) -> activity.AggregatedActivity:
1941        return activity.AggregatedActivity(
1942            hash=int(payload["activityHash"]),
1943            values=self._deserialize_aggregated_activity_values(payload["values"]),
1944        )

Deserialize a JSON payload of an aggregated activity.

Parameters
Returns
def deserialize_aggregated_activities( self, payload: collections.abc.Mapping[str, typing.Any]) -> Iterator[aiobungie.crates.activity.AggregatedActivity]:
1946    def deserialize_aggregated_activities(
1947        self, payload: typedefs.JSONObject
1948    ) -> iterators.Iterator[activity.AggregatedActivity]:
1949        return iterators.Iterator(
1950            [
1951                self.deserialize_aggregated_activity(activity)
1952                for activity in payload["activities"]
1953            ]
1954        )

Deserialize a JSON payload of an array of aggregated activities.

Parameters
Returns
def deserialize_linked_profiles( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.profile.LinkedProfile:
1956    def deserialize_linked_profiles(
1957        self, payload: typedefs.JSONObject
1958    ) -> profile.LinkedProfile:
1959        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
1960
1961        if raw_profile := payload.get("profiles"):
1962            profiles = tuple(
1963                self.deserialize_destiny_membership(p) for p in raw_profile
1964            )
1965        else:
1966            profiles = ()
1967
1968        error_profiles = ()
1969        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
1970            for raw_error_p in raw_profiles_with_errors:
1971                if "infoCard" in raw_error_p:
1972                    error_profiles = tuple(
1973                        self.deserialize_destiny_membership(error_p)
1974                        for error_p in raw_error_p
1975                    )
1976
1977        return profile.LinkedProfile(
1978            bungie_user=bungie_user,
1979            profiles=profiles,
1980            profiles_with_errors=error_profiles,
1981        )

Deserialize a JSON payload of Bungie.net hard linked profile information.

Parameters
Returns
def deserialize_clan_banners( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
1983    def deserialize_clan_banners(
1984        self, payload: typedefs.JSONObject
1985    ) -> collections.Sequence[clans.ClanBanner]:
1986        if banners := payload.get("clanBannerDecals"):
1987            banner_obj = tuple(
1988                clans.ClanBanner(
1989                    id=int(k),
1990                    foreground=assets.Image(path=v["foregroundPath"]),
1991                    background=assets.Image(path=v["backgroundPath"]),
1992                )
1993                for k, v in banners.items()
1994            )
1995        else:
1996            banner_obj = ()
1997        return banner_obj

Deserialize a JSON array of a clan banners information.

Parameters
Returns
def deserialize_public_milestone_content( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.milestones.MilestoneContent:
1999    def deserialize_public_milestone_content(
2000        self, payload: typedefs.JSONObject
2001    ) -> milestones.MilestoneContent:
2002        if raw_categories := payload.get("itemCategories"):
2003            items_categories = tuple(
2004                milestones.MilestoneItems(
2005                    title=item["title"], hashes=item["itemHashes"]
2006                )
2007                for item in raw_categories
2008            )
2009        else:
2010            items_categories = ()
2011
2012        return milestones.MilestoneContent(
2013            about=typedefs.unknown(payload["about"]),
2014            status=typedefs.unknown(payload["status"]),
2015            tips=payload.get("tips", ()),
2016            items=items_categories,
2017        )

Deserialize a JSON payload of milestone content information.

Parameters
Returns
def deserialize_friend( self, payload: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.friends.Friend:
2019    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2020        bungie_user: user.BungieUser | None = None
2021
2022        if raw_bungie_user := payload.get("bungieNetUser"):
2023            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2024
2025        return friends.Friend(
2026            net=self._net,
2027            id=int(payload["lastSeenAsMembershipId"]),
2028            name=typedefs.unknown(payload["bungieGlobalDisplayName"]),
2029            code=payload.get("bungieGlobalDisplayNameCode"),
2030            relationship=enums.Relationship(payload["relationship"]),
2031            user=bungie_user,
2032            online_status=enums.Presence(payload["onlineStatus"]),
2033            online_title=payload["onlineTitle"],
2034            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2035        )

Deserialize a JSON payload of a Bungie friend information.

Parameters
Returns
def deserialize_friends( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
2037    def deserialize_friends(
2038        self, payload: typedefs.JSONObject
2039    ) -> collections.Sequence[friends.Friend]:
2040        return tuple(self.deserialize_friend(friend) for friend in payload["friends"])

Deserialize a JSON sequence of Bungie friends information.

This is usually used to deserialize the incoming/outgoing friend requests.

Parameters
Returns
def deserialize_friend_requests( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.friends.FriendRequestView:
2042    def deserialize_friend_requests(
2043        self, payload: typedefs.JSONObject
2044    ) -> friends.FriendRequestView:
2045        if raw_incoming_requests := payload.get("incomingRequests"):
2046            incoming = tuple(
2047                self.deserialize_friend(incoming_request)
2048                for incoming_request in raw_incoming_requests
2049            )
2050        else:
2051            incoming = ()
2052
2053        if raw_outgoing_requests := payload.get("outgoingRequests"):
2054            outgoing = tuple(
2055                self.deserialize_friend(outgoing_request)
2056                for outgoing_request in raw_outgoing_requests
2057            )
2058        else:
2059            outgoing = ()
2060
2061        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)

Deserialize a JSON sequence of Bungie friend requests information.

This is used for incoming/outgoing friend requests.

Parameters
Returns
def deserialize_fireteams( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]:
2092    def deserialize_fireteams(
2093        self, payload: typedefs.JSONObject
2094    ) -> collections.Sequence[fireteams.Fireteam]:
2095        if "results" in payload:
2096            fireteams_ = tuple(
2097                self._set_fireteam_fields(
2098                    elem, total_results=int(payload["totalResults"])
2099                )
2100                for elem in payload["results"]
2101            )
2102        else:
2103            fireteams_ = ()
2104        return fireteams_

Deserialize a JSON sequence of Bungie fireteams information.

Parameters
Returns
def deserialize_fireteam_destiny_users( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamUser:
2106    def deserialize_fireteam_destiny_users(
2107        self, payload: typedefs.JSONObject
2108    ) -> fireteams.FireteamUser:
2109        destiny_obj = self.deserialize_destiny_membership(payload)
2110        return fireteams.FireteamUser(
2111            net=self._net,
2112            id=destiny_obj.id,
2113            code=destiny_obj.code,
2114            icon=destiny_obj.icon,
2115            types=destiny_obj.types,
2116            type=destiny_obj.type,
2117            is_public=destiny_obj.is_public,
2118            crossave_override=destiny_obj.crossave_override,
2119            name=destiny_obj.name,
2120            last_seen_name=destiny_obj.last_seen_name,
2121            fireteam_display_name=payload["FireteamDisplayName"],
2122            fireteam_membership_id=enums.MembershipType(
2123                payload["FireteamMembershipType"]
2124            ),
2125        )

Deserialize a JSON payload of Bungie fireteam destiny users information.

Parameters
Returns
def deserialize_fireteam_members( self, payload: collections.abc.Mapping[str, typing.Any], *, alternatives: bool = False) -> collections.abc.Sequence[aiobungie.crates.fireteams.FireteamMember]:
2127    def deserialize_fireteam_members(
2128        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2129    ) -> collections.Sequence[fireteams.FireteamMember]:
2130        members_: list[fireteams.FireteamMember] = []
2131        if members := payload.get("Members" if not alternatives else "Alternates"):
2132            for member in members:
2133                bungie_fields = self.deserialize_partial_bungie_user(member)
2134                members_fields = fireteams.FireteamMember(
2135                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2136                    has_microphone=member["hasMicrophone"],
2137                    character_id=int(member["characterId"]),
2138                    date_joined=time.clean_date(member["dateJoined"]),
2139                    last_platform_invite_date=time.clean_date(
2140                        member["lastPlatformInviteAttemptDate"]
2141                    ),
2142                    last_platform_invite_result=int(
2143                        member["lastPlatformInviteAttemptResult"]
2144                    ),
2145                    net=self._net,
2146                    name=bungie_fields.name,
2147                    id=bungie_fields.id,
2148                    icon=bungie_fields.icon,
2149                    is_public=bungie_fields.is_public,
2150                    crossave_override=bungie_fields.crossave_override,
2151                    types=bungie_fields.types,
2152                    type=bungie_fields.type,
2153                )
2154                members_.append(members_fields)
2155        return tuple(members_)

Deserialize a JSON sequence of Bungie fireteam members information.

Parameters
  • payload (aiobungie.typedefs.JSONObject): The JSON payload.
  • alternatives (bool): If set to True, Then it will deserialize the alternatives data in the payload. If not the it will just deserialize the members data.
Returns
def deserialize_available_fireteam( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.fireteams.AvailableFireteam:
2157    def deserialize_available_fireteam(
2158        self, payload: typedefs.JSONObject
2159    ) -> fireteams.AvailableFireteam:
2160        fields = self._set_fireteam_fields(payload["Summary"])
2161        return fireteams.AvailableFireteam(
2162            id=fields.id,
2163            group_id=fields.group_id,
2164            platform=fields.platform,
2165            activity_type=fields.activity_type,
2166            is_immediate=fields.is_immediate,
2167            is_public=fields.is_public,
2168            is_valid=fields.is_valid,
2169            owner_id=fields.owner_id,
2170            player_slot_count=fields.player_slot_count,
2171            available_player_slots=fields.available_player_slots,
2172            available_alternate_slots=fields.available_alternate_slots,
2173            title=fields.title,
2174            date_created=fields.date_created,
2175            locale=fields.locale,
2176            last_modified=fields.last_modified,
2177            total_results=fields.total_results,
2178            scheduled_time=fields.scheduled_time,
2179            date_modified=fields.date_modified,
2180            members=self.deserialize_fireteam_members(payload),
2181            alternatives=self.deserialize_fireteam_members(payload, alternatives=True),
2182        )

Deserialize a JSON payload of a sequence of/fireteam information.

Parameters
Returns
  • An available fireteam object.
def deserialize_available_fireteams( self, data: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]:
2184    def deserialize_available_fireteams(
2185        self, data: typedefs.JSONObject
2186    ) -> collections.Sequence[fireteams.AvailableFireteam]:
2187        if raw_results := data.get("results"):
2188            fireteam_results = tuple(
2189                self.deserialize_available_fireteam(f) for f in raw_results
2190            )
2191        else:
2192            fireteam_results = ()
2193        return fireteam_results

Deserialize a JSON payload sequence of fireteam objects.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.fireteams.AvailableFireteam]: A sequence of available fireteams.
def deserialize_fireteam_party( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamParty:
2195    def deserialize_fireteam_party(
2196        self, payload: typedefs.JSONObject
2197    ) -> fireteams.FireteamParty:
2198        last_destination_hash: int | None = None
2199        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2200            last_destination_hash = int(raw_dest_hash)
2201
2202        return fireteams.FireteamParty(
2203            members=tuple(
2204                self._deserialize_fireteam_party_member(member)
2205                for member in payload["partyMembers"]
2206            ),
2207            activity=self._deserialize_fireteam_party_current_activity(
2208                payload["currentActivity"]
2209            ),
2210            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2211            last_destination_hash=last_destination_hash,
2212            tracking=payload["tracking"],
2213        )

Deserialize a JSON payload of profileTransitory component response.

Parameters
Returns
def deserialize_seasonal_artifact( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.season.Artifact:
2256    def deserialize_seasonal_artifact(
2257        self, payload: typedefs.JSONObject
2258    ) -> season.Artifact:
2259        raw_artifact = payload["seasonalArtifact"]
2260
2261        points = raw_artifact["pointProgression"]
2262        points_prog = progressions.Progression(
2263            hash=points["progressionHash"],
2264            level=points["level"],
2265            cap=points["levelCap"],
2266            daily_limit=points["dailyLimit"],
2267            weekly_limit=points["weeklyLimit"],
2268            current_progress=points["currentProgress"],
2269            daily_progress=points["dailyProgress"],
2270            needed=points["progressToNextLevel"],
2271            next_level=points["nextLevelAt"],
2272        )
2273
2274        bonus = raw_artifact["powerBonusProgression"]
2275        power_bonus_prog = progressions.Progression(
2276            hash=bonus["progressionHash"],
2277            level=bonus["level"],
2278            cap=bonus["levelCap"],
2279            daily_limit=bonus["dailyLimit"],
2280            weekly_limit=bonus["weeklyLimit"],
2281            current_progress=bonus["currentProgress"],
2282            daily_progress=bonus["dailyProgress"],
2283            needed=bonus["progressToNextLevel"],
2284            next_level=bonus["nextLevelAt"],
2285        )
2286        return season.Artifact(
2287            hash=raw_artifact["artifactHash"],
2288            power_bonus=raw_artifact["powerBonus"],
2289            acquired_points=raw_artifact["pointsAcquired"],
2290            bonus=power_bonus_prog,
2291            points=points_prog,
2292        )

Deserialize a JSON payload of a Destiny 2 seasonal artifact information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_profile_progression( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.profile.ProfileProgression:
2294    def deserialize_profile_progression(
2295        self, payload: typedefs.JSONObject
2296    ) -> profile.ProfileProgression:
2297        return profile.ProfileProgression(
2298            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2299            checklist={
2300                int(check_id): checklists
2301                for check_id, checklists in payload["data"]["checklists"].items()
2302            },
2303        )

Deserialize a JSON payload of a profile progression component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_instanced_item( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.items.ItemInstance:
2305    def deserialize_instanced_item(
2306        self, payload: typedefs.JSONObject
2307    ) -> items.ItemInstance:
2308        damage_type_hash: int | None = None
2309        if raw_damagetype_hash := payload.get("damageTypeHash"):
2310            damage_type_hash = int(raw_damagetype_hash)
2311
2312        required_hashes: typing.Optional[collections.Collection[int]] = None
2313        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2314            required_hashes = tuple(int(raw_hash) for raw_hash in raw_required_hashes)
2315
2316        breaker_type: items.ItemBreakerType | None = None
2317        if raw_break_type := payload.get("breakerType"):
2318            breaker_type = items.ItemBreakerType(int(raw_break_type))
2319
2320        breaker_type_hash: int | None = None
2321        if raw_break_type_hash := payload.get("breakerTypeHash"):
2322            breaker_type_hash = int(raw_break_type_hash)
2323
2324        energy: items.ItemEnergy | None = None
2325        if raw_energy := payload.get("energy"):
2326            energy = self.deserialize_item_energy(raw_energy)
2327
2328        primary_stats = None
2329        if raw_primary_stats := payload.get("primaryStat"):
2330            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2331
2332        return items.ItemInstance(
2333            damage_type=enums.DamageType(int(payload["damageType"])),
2334            damage_type_hash=damage_type_hash,
2335            primary_stat=primary_stats,
2336            item_level=int(payload["itemLevel"]),
2337            quality=int(payload["quality"]),
2338            is_equipped=payload["isEquipped"],
2339            can_equip=payload["canEquip"],
2340            equip_required_level=int(payload["equipRequiredLevel"]),
2341            required_equip_unlock_hashes=required_hashes,
2342            cant_equip_reason=int(payload["cannotEquipReason"]),
2343            breaker_type=breaker_type,
2344            breaker_type_hash=breaker_type_hash,
2345            energy=energy,
2346        )

Deserialize a JSON object into an instanced item.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_item_energy( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.items.ItemEnergy:
2348    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2349        energy_hash: int | None = None
2350        if raw_energy_hash := payload.get("energyTypeHash"):
2351            energy_hash = int(raw_energy_hash)
2352
2353        return items.ItemEnergy(
2354            hash=energy_hash,
2355            type=items.ItemEnergyType(int(payload["energyType"])),
2356            capacity=int(payload["energyCapacity"]),
2357            used_energy=int(payload["energyUsed"]),
2358            unused_energy=int(payload["energyUnused"]),
2359        )
def deserialize_item_perk( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.items.ItemPerk:
2361    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2362        perk_hash: int | None = None
2363        if raw_perk_hash := payload.get("perkHash"):
2364            perk_hash = int(raw_perk_hash)
2365
2366        return items.ItemPerk(
2367            hash=perk_hash,
2368            icon=assets.Image(path=payload["iconPath"]),
2369            is_active=payload["isActive"],
2370            is_visible=payload["visible"],
2371        )
def deserialize_item_socket( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.items.ItemSocket:
2373    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2374        plug_hash: int | None = None
2375        if raw_plug_hash := payload.get("plugHash"):
2376            plug_hash = int(raw_plug_hash)
2377
2378        enable_fail_indexes: collections.Sequence[int] | None = None
2379        if raw_indexes := payload.get("enableFailIndexes"):
2380            enable_fail_indexes = tuple(int(index) for index in raw_indexes)
2381
2382        return items.ItemSocket(
2383            plug_hash=plug_hash,
2384            is_enabled=payload["isEnabled"],
2385            enable_fail_indexes=enable_fail_indexes,
2386            is_visible=payload.get("visible"),
2387        )
def deserialize_item_stats_view( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.items.ItemStatsView:
2389    def deserialize_item_stats_view(
2390        self, payload: typedefs.JSONObject
2391    ) -> items.ItemStatsView:
2392        return items.ItemStatsView(
2393            stat_hash=payload.get("statHash"), value=payload.get("value")
2394        )
def deserialize_plug_item_state( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.items.PlugItemState:
2396    def deserialize_plug_item_state(
2397        self, payload: typedefs.JSONObject
2398    ) -> items.PlugItemState:
2399        item_hash: int | None = None
2400        if raw_item_hash := payload.get("plugItemHash"):
2401            item_hash = int(raw_item_hash)
2402
2403        insert_fail_indexes: collections.Sequence[int] | None = None
2404        if raw_fail_indexes := payload.get("insertFailIndexes"):
2405            insert_fail_indexes = tuple(int(k) for k in raw_fail_indexes)
2406
2407        enable_fail_indexes: collections.Sequence[int] | None = None
2408        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2409            enable_fail_indexes = tuple(int(k) for k in raw_enabled_indexes)
2410
2411        return items.PlugItemState(
2412            item_hash=item_hash,
2413            insert_fail_indexes=insert_fail_indexes,
2414            enable_fail_indexes=enable_fail_indexes,
2415            is_enabled=payload["enabled"],
2416            can_insert=payload["canInsert"],
2417        )
@typing.final
class FireteamActivity(builtins.int, aiobungie.Enum):
 65@typing.final
 66class FireteamActivity(int, enums.Enum):
 67    """An enum for the fireteam activities."""
 68
 69    ALL = 0
 70    CRUCIBLE = 2
 71    TRIALS_OF_OSIRIS = 3
 72    NIGHTFALL = 4
 73    ANY = 5
 74    GAMBIT = 6
 75    BLIND_WELL = 7
 76    NIGHTMARE_HUNTS = 12
 77    ALTARS_OF_SORROWS = 14
 78    DUNGEON = 15
 79    RAID_LW = 20
 80    RAID_GOS = 21
 81    RAID_DSC = 22
 82    EXO_CHALLENGE = 23
 83    S12_WRATHBORN = 24
 84    EMPIRE_HUNTS = 25
 85    S13_BATTLEGROUNDS = 26
 86    EXOTIC_QUEST = 27
 87    RAID_VOG = 28
 88    S14_EXPUNGE = 30
 89    S15_ASTRAL_ALIGNMENT = 31
 90    S15_SHATTERED_RELAM = 32
 91    SHATTERED_THRONE = 33
 92    PROPHECY = 34
 93    PIT_OF_HERESY = 35
 94    DOE = 36
 95    """Dares of Eternity."""
 96    DUNGEON_GOA = 37
 97    """Grasp of Avarice."""
 98    VOW_OF_THE_DISCPILE = 38
 99    CAMPAIGN = 39
100    WELLSPRING = 40
101    S16_BATTLEGROUNDS = 41
102    S17_NIGHTMARE_CONTAINMENT = 44
103    S17_SEVER = 45

An enum for the fireteam activities.

CRUCIBLE = <FireteamActivity.CRUCIBLE: 2>
TRIALS_OF_OSIRIS = <FireteamActivity.TRIALS_OF_OSIRIS: 3>
NIGHTFALL = <FireteamActivity.NIGHTFALL: 4>
GAMBIT = <FireteamActivity.GAMBIT: 6>
BLIND_WELL = <FireteamActivity.BLIND_WELL: 7>
NIGHTMARE_HUNTS = <FireteamActivity.NIGHTMARE_HUNTS: 12>
ALTARS_OF_SORROWS = <FireteamActivity.ALTARS_OF_SORROWS: 14>
DUNGEON = <FireteamActivity.DUNGEON: 15>
RAID_LW = <FireteamActivity.RAID_LW: 20>
RAID_GOS = <FireteamActivity.RAID_GOS: 21>
RAID_DSC = <FireteamActivity.RAID_DSC: 22>
EXO_CHALLENGE = <FireteamActivity.EXO_CHALLENGE: 23>
S12_WRATHBORN = <FireteamActivity.S12_WRATHBORN: 24>
EMPIRE_HUNTS = <FireteamActivity.EMPIRE_HUNTS: 25>
S13_BATTLEGROUNDS = <FireteamActivity.S13_BATTLEGROUNDS: 26>
EXOTIC_QUEST = <FireteamActivity.EXOTIC_QUEST: 27>
RAID_VOG = <FireteamActivity.RAID_VOG: 28>
S14_EXPUNGE = <FireteamActivity.S14_EXPUNGE: 30>
S15_ASTRAL_ALIGNMENT = <FireteamActivity.S15_ASTRAL_ALIGNMENT: 31>
S15_SHATTERED_RELAM = <FireteamActivity.S15_SHATTERED_RELAM: 32>
SHATTERED_THRONE = <FireteamActivity.SHATTERED_THRONE: 33>
PROPHECY = <FireteamActivity.PROPHECY: 34>
PIT_OF_HERESY = <FireteamActivity.PIT_OF_HERESY: 35>
DOE = <FireteamActivity.DOE: 36>

Dares of Eternity.

DUNGEON_GOA = <FireteamActivity.DUNGEON_GOA: 37>

Grasp of Avarice.

VOW_OF_THE_DISCPILE = <FireteamActivity.VOW_OF_THE_DISCPILE: 38>
CAMPAIGN = <FireteamActivity.CAMPAIGN: 39>
WELLSPRING = <FireteamActivity.WELLSPRING: 40>
S16_BATTLEGROUNDS = <FireteamActivity.S16_BATTLEGROUNDS: 41>
S17_NIGHTMARE_CONTAINMENT = <FireteamActivity.S17_NIGHTMARE_CONTAINMENT: 44>
S17_SEVER = <FireteamActivity.S17_SEVER: 45>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class FireteamDate(builtins.int, aiobungie.Enum):
129@typing.final
130class FireteamDate(int, enums.Enum):
131    """An enum for fireteam date ranges."""
132
133    ALL = 0
134    NOW = 1
135    TODAY = 2
136    TWO_DAYS = 3
137    THIS_WEEK = 4

An enum for fireteam date ranges.

ALL = <FireteamDate.ALL: 0>
NOW = <FireteamDate.NOW: 1>
TODAY = <FireteamDate.TODAY: 2>
TWO_DAYS = <FireteamDate.TWO_DAYS: 3>
THIS_WEEK = <FireteamDate.THIS_WEEK: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class FireteamLanguage(builtins.str, aiobungie.Enum):
106@typing.final
107class FireteamLanguage(str, enums.Enum):
108    """An enum for fireteams languages filters."""
109
110    ALL = ""
111    ENGLISH = "en"
112    FRENCH = "fr"
113    ESPANOL = "es"
114    DEUTSCH = "de"
115    ITALIAN = "it"
116    JAPANESE = "ja"
117    PORTUGUESE = "pt-br"
118    RUSSIAN = "ru"
119    POLISH = "pl"
120    KOREAN = "ko"
121    # ? China
122    ZH_CHT = "zh-cht"
123    ZH_CHS = "zh-chs"
124
125    def __str__(self) -> str:
126        return str(self.value)

An enum for fireteams languages filters.

ENGLISH = <FireteamLanguage.ENGLISH: en>
FRENCH = <FireteamLanguage.FRENCH: fr>
ESPANOL = <FireteamLanguage.ESPANOL: es>
DEUTSCH = <FireteamLanguage.DEUTSCH: de>
ITALIAN = <FireteamLanguage.ITALIAN: it>
JAPANESE = <FireteamLanguage.JAPANESE: ja>
PORTUGUESE = <FireteamLanguage.PORTUGUESE: pt-br>
RUSSIAN = <FireteamLanguage.RUSSIAN: ru>
POLISH = <FireteamLanguage.POLISH: pl>
KOREAN = <FireteamLanguage.KOREAN: ko>
ZH_CHT = <FireteamLanguage.ZH_CHT: zh-cht>
ZH_CHS = <FireteamLanguage.ZH_CHS: zh-chs>
Inherited Members
Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
@typing.final
class FireteamPlatform(builtins.int, aiobungie.Enum):
52@typing.final
53class FireteamPlatform(int, enums.Enum):
54    """An enum for fireteam related to bungie fireteams.
55    This is different from the normal `aiobungie.MembershipType`.
56    """
57
58    ANY = 0
59    PSN_NETWORK = 1
60    XBOX_LIVE = 2
61    STEAM = 4
62    STADIA = 5

An enum for fireteam related to bungie fireteams. This is different from the normal aiobungie.MembershipType.

PSN_NETWORK = <FireteamPlatform.PSN_NETWORK: 1>
XBOX_LIVE = <FireteamPlatform.XBOX_LIVE: 2>
STEAM = <FireteamPlatform.STEAM: 4>
STADIA = <FireteamPlatform.STADIA: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
class Flag(enum.Flag):
 90class Flag(__enum.Flag):
 91    """Builtin Python enum flag with extra handlings."""
 92
 93    # Needs to type this here for mypy
 94    _value_: int
 95
 96    @property
 97    def name(self) -> str:
 98        if self._name_ is None:
 99            self._name_ = f"UNKNOWN {self._value_}"
100
101        return self._name_
102
103    @property
104    def value(self) -> int:
105        return self._value_
106
107    def __str__(self) -> str:
108        return self.name
109
110    def __repr__(self) -> str:
111        return f"<{type(self).__name__}.{self.name}: {self._value_!s}>"
112
113    def __int__(self) -> int:
114        return int(self.value)
115
116    def __or__(self, other: Flag | int) -> Flag:
117        return self.__class__(self._value_ | int(other))
118
119    def __xor__(self, other: Flag | int) -> Flag:
120        return self.__class__(self._value_ ^ int(other))
121
122    def __and__(self, other: Flag | int) -> Flag:
123        return self.__class__(other & int(other))
124
125    def __invert__(self) -> Flag:
126        return self.__class__(~self._value_)
127
128    def __contains__(self, other: Flag | int) -> bool:
129        return self.value & int(other) == int(other)

Builtin Python enum flag with extra handlings.

name: str
 96    @property
 97    def name(self) -> str:
 98        if self._name_ is None:
 99            self._name_ = f"UNKNOWN {self._value_}"
100
101        return self._name_

The name of the Enum member.

value: int
103    @property
104    def value(self) -> int:
105        return self._value_

The value of the Enum member.

@attrs.define(auto_exc=True)
class Forbidden(aiobungie.HTTPException):
136@attrs.define(auto_exc=True)
137class Forbidden(HTTPException):
138    """Exception that's raised for when status code 403 occurs."""
139
140    http_status: http.HTTPStatus = attrs.field(
141        default=http.HTTPStatus.FORBIDDEN, init=False
142    )

Exception that's raised for when status code 403 occurs.

Forbidden( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Forbidden.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
add_note
args
@typing.final
class GameMode(builtins.int, aiobungie.Enum):
258@typing.final
259class GameMode(int, Enum):
260    """An Enum for all available gamemodes in Destiny 2."""
261
262    NONE = 0
263    STORY = 2
264    STRIKE = 3
265    RAID = 4
266    ALLPVP = 5
267    PATROL = 6
268    ALLPVE = 7
269    RESERVED9 = 9
270    CONTROL = 10
271    RESERVED11 = 11
272    CLASH = 12
273    RESERVED13 = 13
274    CRIMSONDOUBLES = 15
275    NIGHTFALL = 16
276    HEROICNIGHTFALL = 17
277    ALLSTRIKES = 18
278    IRONBANNER = 19
279    RESERVED20 = 20
280    RESERVED21 = 21
281    RESERVED22 = 22
282    RESERVED24 = 24
283    ALLMAYHEM = 25
284    RESERVED26 = 26
285    RESERVED27 = 27
286    RESERVED28 = 28
287    RESERVED29 = 29
288    RESERVED30 = 30
289    SUPREMACY = 31
290    PRIVATEMATCHESALL = 32
291    SURVIVAL = 37
292    COUNTDOWN = 38
293    TRIALSOFTHENINE = 39
294    SOCIAL = 40
295    TRIALSCOUNTDOWN = 41
296    TRIALSSURVIVAL = 42
297    IRONBANNERCONTROL = 43
298    IRONBANNERCLASH = 44
299    IRONBANNERSUPREMACY = 45
300    SCOREDNIGHTFALL = 46
301    SCOREDHEROICNIGHTFALL = 47
302    RUMBLE = 48
303    ALLDOUBLES = 49
304    DOUBLES = 50
305    PRIVATEMATCHESCLASH = 51
306    PRIVATEMATCHESCONTROL = 52
307    PRIVATEMATCHESSUPREMACY = 53
308    PRIVATEMATCHESCOUNTDOWN = 54
309    PRIVATEMATCHESSURVIVAL = 55
310    PRIVATEMATCHESMAYHEM = 56
311    PRIVATEMATCHESRUMBLE = 57
312    HEROICADVENTURE = 58
313    SHOWDOWN = 59
314    LOCKDOWN = 60
315    SCORCHED = 61
316    SCORCHEDTEAM = 62
317    GAMBIT = 63
318    ALLPVECOMPETITIVE = 64
319    BREAKTHROUGH = 65
320    BLACKARMORYRUN = 66
321    SALVAGE = 67
322    IRONBANNERSALVAGE = 68
323    PVPCOMPETITIVE = 69
324    PVPQUICKPLAY = 70
325    CLASHQUICKPLAY = 71
326    CLASHCOMPETITIVE = 72
327    CONTROLQUICKPLAY = 73
328    CONTROLCOMPETITIVE = 74
329    GAMBITPRIME = 75
330    RECKONING = 76
331    MENAGERIE = 77
332    VEXOFFENSIVE = 78
333    NIGHTMAREHUNT = 79
334    ELIMINATION = 80
335    MOMENTUM = 81
336    DUNGEON = 82
337    SUNDIAL = 83
338    TRIALS_OF_OSIRIS = 84
339    DARES = 85
340    OFFENSIVE = 86
341    LOSTSECTOR = 87
342    RIFT = 88
343    ZONECONTROL = 89
344    IRONBANNERRIFT = 90

An Enum for all available gamemodes in Destiny 2.

NONE = <GameMode.NONE: 0>
STORY = <GameMode.STORY: 2>
STRIKE = <GameMode.STRIKE: 3>
RAID = <GameMode.RAID: 4>
ALLPVP = <GameMode.ALLPVP: 5>
PATROL = <GameMode.PATROL: 6>
ALLPVE = <GameMode.ALLPVE: 7>
RESERVED9 = <GameMode.RESERVED9: 9>
CONTROL = <GameMode.CONTROL: 10>
RESERVED11 = <GameMode.RESERVED11: 11>
CLASH = <GameMode.CLASH: 12>
RESERVED13 = <GameMode.RESERVED13: 13>
CRIMSONDOUBLES = <GameMode.CRIMSONDOUBLES: 15>
NIGHTFALL = <GameMode.NIGHTFALL: 16>
HEROICNIGHTFALL = <GameMode.HEROICNIGHTFALL: 17>
ALLSTRIKES = <GameMode.ALLSTRIKES: 18>
IRONBANNER = <GameMode.IRONBANNER: 19>
RESERVED20 = <GameMode.RESERVED20: 20>
RESERVED21 = <GameMode.RESERVED21: 21>
RESERVED22 = <GameMode.RESERVED22: 22>
RESERVED24 = <GameMode.RESERVED24: 24>
ALLMAYHEM = <GameMode.ALLMAYHEM: 25>
RESERVED26 = <GameMode.RESERVED26: 26>
RESERVED27 = <GameMode.RESERVED27: 27>
RESERVED28 = <GameMode.RESERVED28: 28>
RESERVED29 = <GameMode.RESERVED29: 29>
RESERVED30 = <GameMode.RESERVED30: 30>
SUPREMACY = <GameMode.SUPREMACY: 31>
PRIVATEMATCHESALL = <GameMode.PRIVATEMATCHESALL: 32>
SURVIVAL = <GameMode.SURVIVAL: 37>
COUNTDOWN = <GameMode.COUNTDOWN: 38>
TRIALSOFTHENINE = <GameMode.TRIALSOFTHENINE: 39>
SOCIAL = <GameMode.SOCIAL: 40>
TRIALSCOUNTDOWN = <GameMode.TRIALSCOUNTDOWN: 41>
TRIALSSURVIVAL = <GameMode.TRIALSSURVIVAL: 42>
IRONBANNERCONTROL = <GameMode.IRONBANNERCONTROL: 43>
IRONBANNERCLASH = <GameMode.IRONBANNERCLASH: 44>
IRONBANNERSUPREMACY = <GameMode.IRONBANNERSUPREMACY: 45>
SCOREDNIGHTFALL = <GameMode.SCOREDNIGHTFALL: 46>
SCOREDHEROICNIGHTFALL = <GameMode.SCOREDHEROICNIGHTFALL: 47>
RUMBLE = <GameMode.RUMBLE: 48>
ALLDOUBLES = <GameMode.ALLDOUBLES: 49>
DOUBLES = <GameMode.DOUBLES: 50>
PRIVATEMATCHESCLASH = <GameMode.PRIVATEMATCHESCLASH: 51>
PRIVATEMATCHESCONTROL = <GameMode.PRIVATEMATCHESCONTROL: 52>
PRIVATEMATCHESSUPREMACY = <GameMode.PRIVATEMATCHESSUPREMACY: 53>
PRIVATEMATCHESCOUNTDOWN = <GameMode.PRIVATEMATCHESCOUNTDOWN: 54>
PRIVATEMATCHESSURVIVAL = <GameMode.PRIVATEMATCHESSURVIVAL: 55>
PRIVATEMATCHESMAYHEM = <GameMode.PRIVATEMATCHESMAYHEM: 56>
PRIVATEMATCHESRUMBLE = <GameMode.PRIVATEMATCHESRUMBLE: 57>
HEROICADVENTURE = <GameMode.HEROICADVENTURE: 58>
SHOWDOWN = <GameMode.SHOWDOWN: 59>
LOCKDOWN = <GameMode.LOCKDOWN: 60>
SCORCHED = <GameMode.SCORCHED: 61>
SCORCHEDTEAM = <GameMode.SCORCHEDTEAM: 62>
GAMBIT = <GameMode.GAMBIT: 63>
ALLPVECOMPETITIVE = <GameMode.ALLPVECOMPETITIVE: 64>
BREAKTHROUGH = <GameMode.BREAKTHROUGH: 65>
BLACKARMORYRUN = <GameMode.BLACKARMORYRUN: 66>
SALVAGE = <GameMode.SALVAGE: 67>
IRONBANNERSALVAGE = <GameMode.IRONBANNERSALVAGE: 68>
PVPCOMPETITIVE = <GameMode.PVPCOMPETITIVE: 69>
PVPQUICKPLAY = <GameMode.PVPQUICKPLAY: 70>
CLASHQUICKPLAY = <GameMode.CLASHQUICKPLAY: 71>
CLASHCOMPETITIVE = <GameMode.CLASHCOMPETITIVE: 72>
CONTROLQUICKPLAY = <GameMode.CONTROLQUICKPLAY: 73>
CONTROLCOMPETITIVE = <GameMode.CONTROLCOMPETITIVE: 74>
GAMBITPRIME = <GameMode.GAMBITPRIME: 75>
RECKONING = <GameMode.RECKONING: 76>
MENAGERIE = <GameMode.MENAGERIE: 77>
VEXOFFENSIVE = <GameMode.VEXOFFENSIVE: 78>
NIGHTMAREHUNT = <GameMode.NIGHTMAREHUNT: 79>
ELIMINATION = <GameMode.ELIMINATION: 80>
MOMENTUM = <GameMode.MOMENTUM: 81>
DUNGEON = <GameMode.DUNGEON: 82>
SUNDIAL = <GameMode.SUNDIAL: 83>
TRIALS_OF_OSIRIS = <GameMode.TRIALS_OF_OSIRIS: 84>
DARES = <GameMode.DARES: 85>
OFFENSIVE = <GameMode.OFFENSIVE: 86>
LOSTSECTOR = <GameMode.LOSTSECTOR: 87>
RIFT = <GameMode.RIFT: 88>
ZONECONTROL = <GameMode.ZONECONTROL: 89>
IRONBANNERRIFT = <GameMode.IRONBANNERRIFT: 90>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class GatingScope(builtins.int, aiobungie.Enum):
57@typing.final
58class GatingScope(int, enums.Enum):
59    """An enum represents restrictive type of gating that is being performed by an entity.
60
61    This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity
62    applies to everyone equally, or to their specific Profile or Character states.
63    """
64
65    NONE = 0
66    GLOBAL = 1
67    CLAN = 2
68    PROFILE = 3
69    CHARACTER = 4
70    ITEM = 5
71    ASSUMED_WORST_CASE = 6

An enum represents restrictive type of gating that is being performed by an entity.

This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity applies to everyone equally, or to their specific Profile or Character states.

NONE = <GatingScope.NONE: 0>
GLOBAL = <GatingScope.GLOBAL: 1>
CLAN = <GatingScope.CLAN: 2>
PROFILE = <GatingScope.PROFILE: 3>
CHARACTER = <GatingScope.CHARACTER: 4>
ITEM = <GatingScope.ITEM: 5>
ASSUMED_WORST_CASE = <GatingScope.ASSUMED_WORST_CASE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Gender(builtins.int, aiobungie.Enum):
476@typing.final
477class Gender(int, Enum):
478    """An Enum for Destiny Genders."""
479
480    MALE = 0
481    FEMALE = 1
482    UNKNOWN = 2

An Enum for Destiny Genders.

MALE = <Gender.MALE: 0>
FEMALE = <Gender.FEMALE: 1>
UNKNOWN = <Gender.UNKNOWN: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class GroupType(builtins.int, aiobungie.Enum):
645@typing.final
646class GroupType(int, Enum):
647    """An enums for the known bungie group types."""
648
649    GENERAL = 0
650    CLAN = 1

An enums for the known bungie group types.

GENERAL = <GroupType.GENERAL: 0>
CLAN = <GroupType.CLAN: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class HTTPError(aiobungie.AiobungieError):
75@attrs.define(auto_exc=True)
76class HTTPError(AiobungieError):
77    """Base HTTP request errors exception."""
78
79    message: str
80    """The error message."""
81
82    http_status: http.HTTPStatus
83    """The response status."""

Base HTTP request errors exception.

HTTPError(message: str, http_status: http.HTTPStatus)
2def __init__(self, message, http_status):
3    self.message = message
4    self.http_status = http_status
5    BaseException.__init__(self, self.message,self.http_status)

Method generated by attrs for class HTTPError.

message: str

The error message.

http_status: http.HTTPStatus

The response status.

Inherited Members
builtins.BaseException
with_traceback
add_note
args
@attrs.define(auto_exc=True, kw_only=True)
class HTTPException(aiobungie.HTTPError):
 86@attrs.define(auto_exc=True, kw_only=True)
 87class HTTPException(HTTPError):
 88    """An in-depth HTTP exception that's raised with more information."""
 89
 90    error_code: int
 91    """The returned Bungie error status code."""
 92
 93    http_status: http.HTTPStatus
 94    """The request response http status."""
 95
 96    throttle_seconds: int
 97    """The Bungie response throttle seconds."""
 98
 99    url: typedefs.StrOrURL | None
100    """The URL/endpoint caused this error."""
101
102    body: typing.Any
103    """The response body."""
104
105    headers: multidict.CIMultiDictProxy[str]
106    """The response headers."""
107
108    message: str
109    """A Bungie human readable message describes the cause of the error."""
110
111    error_status: str
112    """A Bungie short error status describes the cause of the error."""
113
114    message_data: dict[str, str]
115    """A dict of string key, value that includes each cause of the error
116    to a message describes information about that error.
117    """
118
119    def __str__(self) -> str:
120        status_name, status_value = (
121            self.http_status.name.replace("_", "").title(),
122            self.http_status.value,
123        )
124        return (
125            f"{status_name}: " + "("
126            f"""
127            http_status: {status_value},
128            message: {self.message if self.message else 'UNDEFINED'},
129            error_status: {self.error_status if self.error_status else 'UNDEFINED'},
130            url: {self.url if self.url else 'UNDEFINED'},
131            message_data: {self.message_data}
132        """ + ")"
133        )

An in-depth HTTP exception that's raised with more information.

HTTPException( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class HTTPException.

error_code: int

The returned Bungie error status code.

http_status: http.HTTPStatus

The request response http status.

throttle_seconds: int

The Bungie response throttle seconds.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

message: str

A Bungie human readable message describes the cause of the error.

error_status: str

A Bungie short error status describes the cause of the error.

message_data: dict[str, str]

A dict of string key, value that includes each cause of the error to a message describes information about that error.

Inherited Members
builtins.BaseException
with_traceback
add_note
args
@attrs.frozen(kw_only=True, weakref_slot=False)
class Image:
 76@attrs.frozen(kw_only=True, weakref_slot=False)
 77class Image:
 78    """Representation of an image/avatar/picture Bungie resource.
 79
 80    Example
 81    -------
 82    ```py
 83    from aiobungie import Image
 84    img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
 85    print(img)
 86    # https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg
 87
 88    # Save the image to a file.
 89    await img.save("file_name", "/my/path/to/save/to", "jpeg")
 90    ```
 91
 92    Parameters
 93    ----------
 94    path : `str | None`
 95        The path to the image..
 96    """
 97
 98    path: str = attrs.field()
 99
100    @property
101    def is_missing(self) -> bool:
102        return not self.path
103
104    @property
105    def url(self) -> str:
106        """The URL to the image."""
107        return self.create_url()
108
109    @staticmethod
110    def default() -> str:
111        """Returns the path to the missing Bungie image.
112
113        Note
114        ----
115        This returns the path only, If you want an actual image object use `Image.default_or_else()`
116        """
117        return "/img/misc/missing_icon_d2.png"
118
119    @classmethod
120    def default_or_else(cls, path: str | None = None) -> Self:
121        """Return the default image if `path` was `None` otherwise an `Image` object.
122
123        Example
124        -------
125        ```py
126        img = Image.default_or_else(None)
127        print(img.url()) # https://www.bungie.net/img/misc/missing_icon_d2.png
128
129        img = Image.default_or_else("/some_path/image.png")
130        ```
131        """
132        return cls(path=path or Image.default())
133
134    def create_url(self) -> str:
135        """Creates a full URL to the image path.
136
137        Returns
138        -------
139        str
140            The URL to the image.
141        """
142        return f"{url.BASE}/{self.path if self.path else self.default()}"
143
144    async def save(
145        self,
146        file_name: str,
147        path: pathlib.Path | str,
148        *,
149        mime_type: MimeType | str = MimeType.JPEG,
150        executor: concurrent.futures.Executor | None = None,
151    ) -> None:
152        """Saves the image to a file.
153
154        Parameters
155        ----------
156        file_name : `str`
157            A name for the file to save the image to.
158        path : `pathlib.Path | str`
159            A path tp save the image to.
160
161        Other Parameters
162        ----------------
163        mime_type : `MimeType | str`
164            MIME type of the image. Defaults to JPEG.
165        executor : `concurrent.futures.Executor | None`
166            An optional executor to use for writing the bytes of this image.
167
168        Raises
169        ------
170        `FileNotFoundError`
171            If the path provided does not exist.
172        `RuntimeError`
173            If the image could not be saved.
174        `PermissionError`
175            If the path provided is not writable or does not have write permissions.
176        """
177        if isinstance(path, pathlib.Path) and not path.exists():
178            raise FileNotFoundError(f"File does not exist: {path!r}")
179
180        if self.is_missing:
181            return
182
183        path = pathlib.Path(path)
184
185        loop = helpers.get_or_make_loop()
186
187        try:
188            await loop.run_in_executor(
189                executor, _write, path, file_name, mime_type, await self.read()
190            )
191            _LOGGER.info("Saved image to %s", file_name)
192
193        except asyncio.CancelledError:
194            pass
195
196        except Exception as err:
197            raise RuntimeError("Encountered an error while saving image.") from err
198
199    async def read(self) -> bytes:
200        """Read this image bytes.
201
202        Returns
203        -------
204        `bytes`
205            The bytes of this image.
206        """
207        client_session = aiohttp.ClientSession()
208
209        byte = b""
210        try:
211            await client_session.__aenter__()
212            response = await client_session.get(self.create_url())
213
214            if 300 >= response.status >= 200:
215                byte = await response.read()
216
217        except Exception as exc:
218            raise RuntimeError(f"Failed to read image: {exc}") from None
219        finally:
220            await client_session.__aexit__(None, None, None)
221        return byte
222
223    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
224        """Iterates over the image bytes lazily.
225
226        Example
227        -------
228        import aiobungie
229
230        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
231        async for chunk in resource.iter():
232            print(chunk)
233
234        Returns
235        -------
236        `collections.AsyncGenerator[bytes, None]`
237            An async generator of the image bytes.
238        """
239
240        async for chunk in self:
241            yield chunk
242
243    def __repr__(self) -> str:
244        return f"Image(url={self.create_url()})"
245
246    def __str__(self) -> str:
247        return self.create_url()
248
249    def __aiter__(self) -> Image:
250        return self
251
252    async def __anext__(self) -> bytes:
253        return await self.read()
254
255    def __await__(self) -> collections.Generator[None, None, bytes]:
256        return self.__anext__().__await__()

Representation of an image/avatar/picture Bungie resource.

Example
from aiobungie import Image
img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
print(img)
# https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg

# Save the image to a file.
await img.save("file_name", "/my/path/to/save/to", "jpeg")
Parameters
  • path (str | None): The path to the image..
Image(*, path: str)
2def __init__(self, *, path):
3    _setattr = _cached_setattr_get(self)
4    _setattr('path', path)

Method generated by attrs for class Image.

path: str
is_missing: bool
100    @property
101    def is_missing(self) -> bool:
102        return not self.path
url: str
104    @property
105    def url(self) -> str:
106        """The URL to the image."""
107        return self.create_url()

The URL to the image.

@staticmethod
def default() -> str:
109    @staticmethod
110    def default() -> str:
111        """Returns the path to the missing Bungie image.
112
113        Note
114        ----
115        This returns the path only, If you want an actual image object use `Image.default_or_else()`
116        """
117        return "/img/misc/missing_icon_d2.png"

Returns the path to the missing Bungie image.

Note

This returns the path only, If you want an actual image object use Image.default_or_else()

@classmethod
def default_or_else(cls, path: str | None = None) -> Self:
119    @classmethod
120    def default_or_else(cls, path: str | None = None) -> Self:
121        """Return the default image if `path` was `None` otherwise an `Image` object.
122
123        Example
124        -------
125        ```py
126        img = Image.default_or_else(None)
127        print(img.url()) # https://www.bungie.net/img/misc/missing_icon_d2.png
128
129        img = Image.default_or_else("/some_path/image.png")
130        ```
131        """
132        return cls(path=path or Image.default())

Return the default image if path was None otherwise an Image object.

Example
img = Image.default_or_else(None)
print(img.url()) # https://www.bungie.net/img/misc/missing_icon_d2.png

img = Image.default_or_else("/some_path/image.png")
def create_url(self) -> str:
134    def create_url(self) -> str:
135        """Creates a full URL to the image path.
136
137        Returns
138        -------
139        str
140            The URL to the image.
141        """
142        return f"{url.BASE}/{self.path if self.path else self.default()}"

Creates a full URL to the image path.

Returns
  • str: The URL to the image.
async def save( self, file_name: str, path: pathlib.Path | str, *, mime_type: aiobungie.internal.assets.MimeType | str = <MimeType.JPEG: jpeg>, executor: concurrent.futures._base.Executor | None = None) -> None:
144    async def save(
145        self,
146        file_name: str,
147        path: pathlib.Path | str,
148        *,
149        mime_type: MimeType | str = MimeType.JPEG,
150        executor: concurrent.futures.Executor | None = None,
151    ) -> None:
152        """Saves the image to a file.
153
154        Parameters
155        ----------
156        file_name : `str`
157            A name for the file to save the image to.
158        path : `pathlib.Path | str`
159            A path tp save the image to.
160
161        Other Parameters
162        ----------------
163        mime_type : `MimeType | str`
164            MIME type of the image. Defaults to JPEG.
165        executor : `concurrent.futures.Executor | None`
166            An optional executor to use for writing the bytes of this image.
167
168        Raises
169        ------
170        `FileNotFoundError`
171            If the path provided does not exist.
172        `RuntimeError`
173            If the image could not be saved.
174        `PermissionError`
175            If the path provided is not writable or does not have write permissions.
176        """
177        if isinstance(path, pathlib.Path) and not path.exists():
178            raise FileNotFoundError(f"File does not exist: {path!r}")
179
180        if self.is_missing:
181            return
182
183        path = pathlib.Path(path)
184
185        loop = helpers.get_or_make_loop()
186
187        try:
188            await loop.run_in_executor(
189                executor, _write, path, file_name, mime_type, await self.read()
190            )
191            _LOGGER.info("Saved image to %s", file_name)
192
193        except asyncio.CancelledError:
194            pass
195
196        except Exception as err:
197            raise RuntimeError("Encountered an error while saving image.") from err

Saves the image to a file.

Parameters
  • file_name (str): A name for the file to save the image to.
  • path (pathlib.Path | str): A path tp save the image to.
Other Parameters
  • mime_type (MimeType | str): MIME type of the image. Defaults to JPEG.
  • executor (concurrent.futures.Executor | None): An optional executor to use for writing the bytes of this image.
Raises
  • FileNotFoundError: If the path provided does not exist.
  • RuntimeError: If the image could not be saved.
  • PermissionError: If the path provided is not writable or does not have write permissions.
async def read(self) -> bytes:
199    async def read(self) -> bytes:
200        """Read this image bytes.
201
202        Returns
203        -------
204        `bytes`
205            The bytes of this image.
206        """
207        client_session = aiohttp.ClientSession()
208
209        byte = b""
210        try:
211            await client_session.__aenter__()
212            response = await client_session.get(self.create_url())
213
214            if 300 >= response.status >= 200:
215                byte = await response.read()
216
217        except Exception as exc:
218            raise RuntimeError(f"Failed to read image: {exc}") from None
219        finally:
220            await client_session.__aexit__(None, None, None)
221        return byte

Read this image bytes.

Returns
  • bytes: The bytes of this image.
async def iter(self) -> collections.abc.AsyncGenerator[bytes, None]:
223    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
224        """Iterates over the image bytes lazily.
225
226        Example
227        -------
228        import aiobungie
229
230        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
231        async for chunk in resource.iter():
232            print(chunk)
233
234        Returns
235        -------
236        `collections.AsyncGenerator[bytes, None]`
237            An async generator of the image bytes.
238        """
239
240        async for chunk in self:
241            yield chunk

Iterates over the image bytes lazily.

Example

import aiobungie

resource = aiobungie.Image("img/misc/missing_icon_d2.png") async for chunk in resource.iter(): print(chunk)

Returns
  • collections.AsyncGenerator[bytes, None]: An async generator of the image bytes.
@attrs.define(auto_exc=True)
class InternalServerError(aiobungie.HTTPException):
240@attrs.define(auto_exc=True)
241class InternalServerError(HTTPException):
242    """Raised for 5xx internal server errors."""

Raised for 5xx internal server errors.

InternalServerError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class InternalServerError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
add_note
args
@typing.final
class ItemBindStatus(builtins.int, aiobungie.Enum):
711@typing.final
712class ItemBindStatus(int, Enum):
713    """An enum for Destiny 2 items bind status."""
714
715    NOT_BOUND = 0
716    BOUND_TO_CHARACTER = 1
717    BOUND_TO_ACCOUNT = 2
718    BOUNT_TO_GUILD = 3

An enum for Destiny 2 items bind status.

NOT_BOUND = <ItemBindStatus.NOT_BOUND: 0>
BOUND_TO_CHARACTER = <ItemBindStatus.BOUND_TO_CHARACTER: 1>
BOUND_TO_ACCOUNT = <ItemBindStatus.BOUND_TO_ACCOUNT: 2>
BOUNT_TO_GUILD = <ItemBindStatus.BOUNT_TO_GUILD: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class ItemLocation(builtins.int, aiobungie.Enum):
721@typing.final
722class ItemLocation(int, Enum):
723    """An enum for Destiny 2 items location."""
724
725    UNKNOWN = 0
726    INVENTORY = 1
727    VAULT = 2
728    VENDOR = 3
729    POSTMASTER = 4

An enum for Destiny 2 items location.

UNKNOWN = <ItemLocation.UNKNOWN: 0>
INVENTORY = <ItemLocation.INVENTORY: 1>
VAULT = <ItemLocation.VAULT: 2>
VENDOR = <ItemLocation.VENDOR: 3>
POSTMASTER = <ItemLocation.POSTMASTER: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class ItemState(aiobungie.Flag):
746@typing.final
747class ItemState(Flag):
748    """An enum for Destiny 2 item states."""
749
750    NONE = 0
751    LOCKED = 1 << 0
752    TRACKED = 1 << 1
753    MASTERWORKED = 1 << 2
754    CRAFTED = 1 << 3
755    """If this bit is set, the item has been 'crafted' by the player."""
756    HIGHLITED_OBJECTIVE = 1 << 4
757    """If this bit is set, the item is a 'highlighted' objective."""

An enum for Destiny 2 item states.

NONE = <ItemState.NONE: 0>
LOCKED = <ItemState.LOCKED: 1>
TRACKED = <ItemState.TRACKED: 2>
MASTERWORKED = <ItemState.MASTERWORKED: 4>
CRAFTED = <ItemState.CRAFTED: 8>

If this bit is set, the item has been 'crafted' by the player.

HIGHLITED_OBJECTIVE = <ItemState.HIGHLITED_OBJECTIVE: 16>

If this bit is set, the item is a 'highlighted' objective.

Inherited Members
Flag
name
value
@typing.final
class ItemSubType(builtins.int, aiobungie.Enum):
578@typing.final
579class ItemSubType(int, Enum):
580    """An enum for Destiny 2 inventory items subtype."""
581
582    NONE = 0
583    AUTORIFLE = 6
584    SHOTGUN = 7
585    MACHINEGUN = 8
586    HANDCANNON = 9
587    ROCKETLAUNCHER = 10
588    FUSIONRIFLE = 11
589    SNIPERRIFLE = 12
590    PULSERIFLE = 13
591    SCOUTRIFLE = 14
592    SIDEARM = 17
593    SWORD = 18
594    MASK = 19
595    SHADER = 20
596    ORNAMENT = 21
597    FUSIONRIFLELINE = 22
598    GRENADELAUNCHER = 23
599    SUBMACHINEGUN = 24
600    TRACERIFLE = 25
601    HELMETARMOR = 26
602    GAUNTLETSARMOR = 27
603    CHESTARMOR = 28
604    LEGARMOR = 29
605    CLASSARMOR = 30
606    BOW = 31
607    DUMMYREPEATABLEBOUNTY = 32

An enum for Destiny 2 inventory items subtype.

NONE = <ItemSubType.NONE: 0>
AUTORIFLE = <ItemSubType.AUTORIFLE: 6>
SHOTGUN = <ItemSubType.SHOTGUN: 7>
MACHINEGUN = <ItemSubType.MACHINEGUN: 8>
HANDCANNON = <ItemSubType.HANDCANNON: 9>
ROCKETLAUNCHER = <ItemSubType.ROCKETLAUNCHER: 10>
FUSIONRIFLE = <ItemSubType.FUSIONRIFLE: 11>
SNIPERRIFLE = <ItemSubType.SNIPERRIFLE: 12>
PULSERIFLE = <ItemSubType.PULSERIFLE: 13>
SCOUTRIFLE = <ItemSubType.SCOUTRIFLE: 14>
SIDEARM = <ItemSubType.SIDEARM: 17>
SWORD = <ItemSubType.SWORD: 18>
MASK = <ItemSubType.MASK: 19>
SHADER = <ItemSubType.SHADER: 20>
ORNAMENT = <ItemSubType.ORNAMENT: 21>
FUSIONRIFLELINE = <ItemSubType.FUSIONRIFLELINE: 22>
GRENADELAUNCHER = <ItemSubType.GRENADELAUNCHER: 23>
SUBMACHINEGUN = <ItemSubType.SUBMACHINEGUN: 24>
TRACERIFLE = <ItemSubType.TRACERIFLE: 25>
HELMETARMOR = <ItemSubType.HELMETARMOR: 26>
GAUNTLETSARMOR = <ItemSubType.GAUNTLETSARMOR: 27>
CHESTARMOR = <ItemSubType.CHESTARMOR: 28>
LEGARMOR = <ItemSubType.LEGARMOR: 29>
CLASSARMOR = <ItemSubType.CLASSARMOR: 30>
BOW = <ItemSubType.BOW: 31>
DUMMYREPEATABLEBOUNTY = <ItemSubType.DUMMYREPEATABLEBOUNTY: 32>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class ItemTier(builtins.int, aiobungie.Enum):
610@typing.final
611class ItemTier(int, Enum):
612    """An enum for a Destiny 2 item tier."""
613
614    NONE = 0
615    BASIC = 3340296461
616    COMMON = 2395677314
617    RARE = 2127292149
618    LEGENDERY = 4008398120
619    EXOTIC = 2759499571

An enum for a Destiny 2 item tier.

NONE = <ItemTier.NONE: 0>
BASIC = <ItemTier.BASIC: 3340296461>
COMMON = <ItemTier.COMMON: 2395677314>
RARE = <ItemTier.RARE: 2127292149>
LEGENDERY = <ItemTier.LEGENDERY: 4008398120>
EXOTIC = <ItemTier.EXOTIC: 2759499571>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class ItemType(builtins.int, aiobungie.Enum):
545@typing.final
546class ItemType(int, Enum):
547    """Enums for Destiny2's item types."""
548
549    NONE = 0
550    CURRENCY = 1
551    ARMOR = 2
552    WEAPON = 3
553    MESSAGE = 7
554    ENGRAM = 8
555    CONSUMABLE = 9
556    EXCHANGEMATERIAL = 10
557    MISSIONREWARD = 11
558    QUESTSTEP = 12
559    QUESTSTEPCOMPLETE = 13
560    EMBLEM = 14
561    QUEST = 15
562    SUBCLASS = 16
563    CLANBANNER = 17
564    AURA = 18
565    MOD = 19
566    DUMMY = 20
567    SHIP = 21
568    VEHICLE = 22
569    EMOTE = 23
570    GHOST = 24
571    PACKAGE = 25
572    BOUNTY = 26
573    WRAPPER = 27
574    SEASONALARTIFACT = 28
575    FINISHER = 29

Enums for Destiny2's item types.

NONE = <ItemType.NONE: 0>
CURRENCY = <ItemType.CURRENCY: 1>
ARMOR = <ItemType.ARMOR: 2>
WEAPON = <ItemType.WEAPON: 3>
MESSAGE = <ItemType.MESSAGE: 7>
ENGRAM = <ItemType.ENGRAM: 8>
CONSUMABLE = <ItemType.CONSUMABLE: 9>
EXCHANGEMATERIAL = <ItemType.EXCHANGEMATERIAL: 10>
MISSIONREWARD = <ItemType.MISSIONREWARD: 11>
QUESTSTEP = <ItemType.QUESTSTEP: 12>
QUESTSTEPCOMPLETE = <ItemType.QUESTSTEPCOMPLETE: 13>
EMBLEM = <ItemType.EMBLEM: 14>
QUEST = <ItemType.QUEST: 15>
SUBCLASS = <ItemType.SUBCLASS: 16>
CLANBANNER = <ItemType.CLANBANNER: 17>
AURA = <ItemType.AURA: 18>
MOD = <ItemType.MOD: 19>
DUMMY = <ItemType.DUMMY: 20>
SHIP = <ItemType.SHIP: 21>
VEHICLE = <ItemType.VEHICLE: 22>
EMOTE = <ItemType.EMOTE: 23>
GHOST = <ItemType.GHOST: 24>
PACKAGE = <ItemType.PACKAGE: 25>
BOUNTY = <ItemType.BOUNTY: 26>
WRAPPER = <ItemType.WRAPPER: 27>
SEASONALARTIFACT = <ItemType.SEASONALARTIFACT: 28>
FINISHER = <ItemType.FINISHER: 29>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
class Iterator(typing.Generic[~Item], collections.abc.Iterator[~Item]):
 47class Iterator(typing.Generic[Item], collections.Iterator[Item]):
 48    """A Flat, In-Memory iterator for sequenced based data.
 49
 50    Example
 51    -------
 52    ```py
 53    iterator = Iterator([1, 2, 3])
 54
 55    # Map the results.
 56    for item in iterator.map(lambda item: item * 2):
 57        print(item)
 58    # 2
 59    # 4
 60
 61    # Indexing is also supported.
 62    print(iterator[0])
 63    # 1
 64
 65    # Normal iteration.
 66    for item in iterator:
 67        print(item)
 68    # 1
 69    # 2
 70    # 3
 71
 72    # Union two iterators.
 73    iterator2 = Iterator([4, 5, 6])
 74    final = iterator | iterator2
 75    # <Iterator([1, 2, 3, 4, 5, 6])>
 76    ```
 77
 78    Parameters
 79    ----------
 80    items: `collections.Iterable[Item]`
 81        The items to iterate over.
 82    """
 83
 84    __slots__ = ("_items",)
 85
 86    def __init__(self, items: collections.Iterable[Item]) -> None:
 87        self._items = _builtins.iter(items)
 88
 89    @typing.overload
 90    def collect(self) -> collections.Sequence[Item]: ...
 91
 92    @typing.overload
 93    def collect(self, casting: _B) -> collections.Sequence[_B]: ...
 94
 95    def collect(
 96        self, casting: _B | None = None
 97    ) -> collections.Sequence[Item] | collections.Sequence[_B]:
 98        """Collects all items in the iterator into an immutable collection.
 99
100        Example
101        -------
102        >>> iterator = Iterator([1, 2, 3])
103        >>> iterator.collect(casting=str)
104        ("1", "2", "3")
105
106        Parameters
107        ----------
108        casting: `T | None`
109            The type to cast the items to. If `None` is provided, the items will be returned as is.
110
111        Returns
112        -------
113        `collections.Sequence[Item | T]`
114            An immutable sequence of the elements in the iterator.
115
116        Raises
117        ------
118        `StopIteration`
119            If no elements are left in the iterator.
120        """
121        if casting is not None:
122            return typing.cast(
123                collections.Sequence[_B], tuple(map(casting, self._items))
124            )
125
126        return tuple(self._items)
127
128    def copied(self) -> Iterator[Item]:
129        """Creates an iterator which `deeply` copies all of its elements.
130
131        .. warn::
132            This will `deeply` copy all of the elements, Use `Iterator.by_ref`
133            if you want copy of the iterator reference.
134
135        Example
136        -------
137        ```py
138        it = Iterator([None, None, None])
139        copied_iter = it.copied()
140        assert it.collect() == copied.collect()
141        ```
142        """
143        return Iterator(_copy.deepcopy(self._items))
144
145    def by_ref(self) -> Iterator[Item]:
146        """Creates an iterator which doesn't consume its elements.
147        but instead shallow copy it.
148
149        Example
150        -------
151        ```py
152        it = Iterator([None, None, None])
153        for ref in it.by_ref():
154            ...
155
156        # Original not consumed.
157        assert it.count() == 3
158        ```
159        """
160        return Iterator(_copy.copy(self._items))
161
162    def next(self) -> Item:
163        """Returns the next item in the iterator.
164
165        Example
166        -------
167        ```py
168        iterator = Iterator(["1", "2", "3"])
169        item = iterator.next()
170        assert item == "1"
171        item = iterator.next()
172        assert item == "2"
173        ```
174
175        Raises
176        ------
177        `StopIteration`
178            If no elements are left in the iterator.
179        """
180        try:
181            return self.__next__()
182        except StopIteration:
183            self._ok()
184
185    def map(
186        self, predicate: collections.Callable[[Item], OtherItem]
187    ) -> Iterator[OtherItem]:
188        """Maps each item in the iterator to its predicated value.
189
190        Example
191        -------
192        ```py
193        iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
194        print(iterator)
195        # <Iterator([1, 2, 3])>
196        ```
197
198        Parameters
199        ----------
200        predicate: `collections.Callable[[Item], OtherItem]`
201            The function to map each item in the iterator to its predicated value.
202
203        Returns
204        -------
205        `Iterator[OtherItem]`
206            The mapped iterator.
207
208        Raises
209        ------
210        `StopIteration`
211            If no elements are left in the iterator.
212        """
213        return Iterator(map(predicate, self._items))
214
215    def take(self, n: int) -> Iterator[Item]:
216        """Take the first number of items until the number of items are yielded or
217        the end of the iterator is reached.
218
219        Example
220        -------
221        ```py
222        iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
223        print(iterator.take(2))
224        # <Iterator([GameMode.RAID, GameMode.STRIKE])>
225        ```
226
227        Parameters
228        ----------
229        n: `int`
230            The number of items to take.
231
232        Raises
233        ------
234        `StopIteration`
235            If no elements are left in the iterator.
236        """
237        return Iterator(itertools.islice(self._items, n))
238
239    def take_while(
240        self, predicate: collections.Callable[[Item], bool]
241    ) -> Iterator[Item]:
242        """Yields items from the iterator while predicate returns `True`.
243
244        Example
245        -------
246        ```py
247        iterator = Iterator([STEAM, XBOX, STADIA])
248        print(iterator.take_while(lambda platform: platform is not XBOX))
249        # <Iterator([STEAM])>
250        ```
251
252        Parameters
253        ----------
254        predicate: `collections.Callable[[Item], bool]`
255            The function to predicate each item in the iterator.
256
257        Raises
258        ------
259        `StopIteration`
260            If no elements are left in the iterator.
261        """
262        return Iterator(itertools.takewhile(predicate, self._items))
263
264    def drop_while(
265        self, predicate: collections.Callable[[Item], bool]
266    ) -> Iterator[Item]:
267        """Yields items from the iterator while predicate returns `False`.
268
269        Example
270        -------
271        ```py
272        iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
273        print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
274        # <Iterator([DestinyMembership(name="Bob")])>
275        ```
276
277        Parameters
278        ----------
279        predicate: `collections.Callable[[Item], bool]`
280            The function to predicate each item in the iterator.
281
282        Raises
283        ------
284        `StopIteration`
285            If no elements are left in the iterator.
286        """
287        return Iterator(itertools.dropwhile(predicate, self._items))
288
289    def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]:
290        """Filters the iterator to only yield items that match the predicate.
291
292        Example
293        -------
294        ```py
295        names = Iterator(["Jim", "Bob", "Mike", "Jess"])
296        print(names.filter(lambda n: n != "Jim"))
297        # <Iterator(["Bob", "Mike", "Jess"])>
298        ```
299        """
300        return Iterator(filter(predicate, self._items))
301
302    def skip(self, n: int) -> Iterator[Item]:
303        """Skips the first number of items in the iterator.
304
305        Example
306        -------
307        ```py
308        iterator = Iterator([STEAM, XBOX, STADIA])
309        print(iterator.skip(1))
310        # <Iterator([XBOX, STADIA])>
311        ```
312        """
313        return Iterator(itertools.islice(self._items, n, None))
314
315    def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]:
316        """Zips the iterator with another iterable.
317
318        Example
319        -------
320        ```py
321        iterator = Iterator([1, 3, 5])
322        other = Iterator([2, 4, 6])
323        for item, other_item in iterator.zip(other):
324            print(item, other_item)
325        # <Iterator([(1, 2), (3, 4), (5, 6)])>
326        ```
327
328        Parameters
329        ----------
330        other: `Iterator[OtherItem]`
331            The iterable to zip with.
332
333        Raises
334        ------
335        `StopIteration`
336            If no elements are left in the iterator.
337        """
338        return Iterator(zip(self._items, other))
339
340    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
341        """`True` if all items in the iterator match the predicate.
342
343        Example
344        -------
345        ```py
346        iterator = Iterator([1, 2, 3])
347        while iterator.all(lambda item: isinstance(item, int)):
348            print("Still all integers")
349            continue
350        # Still all integers
351        ```
352
353        Parameters
354        ----------
355        predicate: `collections.Callable[[Item], bool]`
356            The function to test each item in the iterator.
357
358        Raises
359        ------
360        `StopIteration`
361            If no elements are left in the iterator.
362        """
363        return all(predicate(item) for item in self)
364
365    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
366        """`True` if any items in the iterator match the predicate.
367
368        Example
369        -------
370        ```py
371        iterator = Iterator([1, 2, 3])
372        if iterator.any(lambda item: isinstance(item, int)):
373            print("At least one item is an int.")
374        # At least one item is an int.
375        ```
376
377        Parameters
378        ----------
379        predicate: `collections.Callable[[Item], bool]`
380            The function to test each item in the iterator.
381
382        Raises
383        ------
384        `StopIteration`
385            If no elements are left in the iterator.
386        """
387        return any(predicate(item) for item in self)
388
389    def sort(
390        self,
391        *,
392        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
393        reverse: bool = False,
394    ) -> Iterator[Item]:
395        """Sorts the iterator.
396
397        Example
398        -------
399        ```py
400        iterator = Iterator([3, 1, 6, 7])
401        print(iterator.sort(key=lambda item: item))
402        # <Iterator([1, 3, 6, 7])>
403        ```
404
405        Parameters
406        ----------
407        key: `collections.Callable[[Item], Any]`
408            The function to sort by.
409        reverse: `bool`
410            Whether to reverse the sort.
411
412        Raises
413        ------
414        `StopIteration`
415            If no elements are left in the iterator.
416        """
417        return Iterator(sorted(self._items, key=key, reverse=reverse))
418
419    def first(self) -> Item:
420        """Returns the first item in the iterator.
421
422        Example
423        -------
424        ```py
425        iterator = Iterator([3, 1, 6, 7])
426        print(iterator.first())
427        3
428        ```
429
430        Raises
431        ------
432        `StopIteration`
433            If no elements are left in the iterator.
434        """
435        return self.take(1).next()
436
437    def last(self) -> Item:
438        """Returns the last item in the iterator.
439
440        Example
441        ------
442        ```py
443        it = Iterator((1, 2, 3))
444        assert it.first() == 1 and it.last() == 3
445        ```
446        """
447        return self.reversed().first()
448
449    def reversed(self) -> Iterator[Item]:
450        """Returns a new iterator that yields the items in the iterator in reverse order.
451
452        Example
453        -------
454        ```py
455        iterator = Iterator([3, 1, 6, 7])
456        print(iterator.reversed())
457        # <Iterator([7, 6, 1, 3])>
458        ```
459
460        Raises
461        ------
462        `StopIteration`
463            If no elements are left in the iterator.
464        """
465        return Iterator(reversed(self.collect()))
466
467    def count(self) -> int:
468        """Returns the number of items in the iterator.
469
470        Example
471        -------
472        ```py
473        iterator = Iterator([3, 1, 6, 7])
474        print(iterator.count())
475        4
476        ```
477        """
478        count = 0
479        for _ in self:
480            count += 1
481
482        return count
483
484    def union(self, other: Iterator[Item]) -> Iterator[Item]:
485        """Returns a new iterator that yields all items from both iterators.
486
487        Example
488        -------
489        ```py
490        iterator = Iterator([1, 2, 3])
491        other = Iterator([4, 5, 6])
492        print(iterator.union(other))
493        # <Iterator([1, 2, 3, 4, 5, 6])>
494        ```
495
496        Parameters
497        ----------
498        other: `Iterator[Item]`
499            The iterable to union with.
500
501        Raises
502        ------
503        `StopIteration`
504            If no elements are left in the iterator.
505        """
506        return Iterator(itertools.chain(self._items, other))
507
508    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
509        """Calls the function on each item in the iterator.
510
511        Example
512        -------
513        ```py
514        iterator = Iterator([1, 2, 3])
515        iterator.for_each(lambda item: print(item))
516        # 1
517        # 2
518        # 3
519        ```
520
521        Parameters
522        ----------
523        func: `typeshed.Callable[[Item], None]`
524            The function to call on each item in the iterator.
525        """
526        for item in self:
527            func(item)
528
529    async def async_for_each(
530        self,
531        func: collections.Callable[[Item], collections.Coroutine[None, None, None]],
532    ) -> None:
533        """Calls the async function on each item in the iterator concurrently.
534
535        Example
536        -------
537        ```py
538        async def signup(username: str) -> None:
539            async with aiohttp.request('POST', '...') as r:
540                # Actual logic.
541                ...
542
543        async def main():
544            users = aiobungie.into_iter(["user_danny", "user_jojo"])
545            await users.async_for_each(lambda username: signup(username))
546        ```
547
548        Parameters
549        ----------
550        func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]`
551            The async function to call on each item in the iterator.
552        """
553        await _helpers.awaits(*(func(item) for item in self))
554
555    def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]:
556        """Returns a new iterator that yields tuples of the index and item.
557
558        Example
559        -------
560        ```py
561        iterator = Iterator([1, 2, 3])
562        for index, item in iterator.enumerate():
563            print(index, item)
564        # 0 1
565        # 1 2
566        # 2 3
567        ```
568
569        Raises
570        ------
571        `StopIteration`
572            If no elements are left in the iterator.
573        """
574        return Iterator(enumerate(self._items, start=start))
575
576    def _ok(self) -> typing.NoReturn:
577        raise StopIteration("No more items in the iterator.") from None
578
579    def __getitem__(self, index: int) -> Item:
580        try:
581            return self.skip(index).first()
582        except IndexError:
583            self._ok()
584
585    def __or__(self, other: Iterator[Item]) -> Iterator[Item]:
586        return self.union(other)
587
588    # This is a never.
589    def __setitem__(self) -> typing.NoReturn:
590        raise TypeError(
591            f"{type(self).__name__} doesn't support item assignment."
592        ) from None
593
594    def __repr__(self) -> str:
595        return f"Iterator(ptr: {hex(id(self._items))})"
596
597    __str__ = __repr__
598
599    def __len__(self) -> int:
600        return self.count()
601
602    def __iter__(self) -> Iterator[Item]:
603        return self
604
605    def __next__(self) -> Item:
606        try:
607            item = next(self._items)
608        except StopIteration:
609            self._ok()
610
611        return item

A Flat, In-Memory iterator for sequenced based data.

Example
iterator = Iterator([1, 2, 3])

# Map the results.
for item in iterator.map(lambda item: item * 2):
    print(item)
# 2
# 4

# Indexing is also supported.
print(iterator[0])
# 1

# Normal iteration.
for item in iterator:
    print(item)
# 1
# 2
# 3

# Union two iterators.
iterator2 = Iterator([4, 5, 6])
final = iterator | iterator2
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
  • items (collections.Iterable[Item]): The items to iterate over.
Iterator(items: collections.abc.Iterable[~Item])
86    def __init__(self, items: collections.Iterable[Item]) -> None:
87        self._items = _builtins.iter(items)
def collect( self, casting: '_B | None' = None) -> 'collections.Sequence[Item] | collections.Sequence[_B]':
 95    def collect(
 96        self, casting: _B | None = None
 97    ) -> collections.Sequence[Item] | collections.Sequence[_B]:
 98        """Collects all items in the iterator into an immutable collection.
 99
100        Example
101        -------
102        >>> iterator = Iterator([1, 2, 3])
103        >>> iterator.collect(casting=str)
104        ("1", "2", "3")
105
106        Parameters
107        ----------
108        casting: `T | None`
109            The type to cast the items to. If `None` is provided, the items will be returned as is.
110
111        Returns
112        -------
113        `collections.Sequence[Item | T]`
114            An immutable sequence of the elements in the iterator.
115
116        Raises
117        ------
118        `StopIteration`
119            If no elements are left in the iterator.
120        """
121        if casting is not None:
122            return typing.cast(
123                collections.Sequence[_B], tuple(map(casting, self._items))
124            )
125
126        return tuple(self._items)

Collects all items in the iterator into an immutable collection.

Example
>>> iterator = Iterator([1, 2, 3])
>>> iterator.collect(casting=str)
("1", "2", "3")
Parameters
  • casting (T | None): The type to cast the items to. If None is provided, the items will be returned as is.
Returns
  • collections.Sequence[Item | T]: An immutable sequence of the elements in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def copied(self) -> Iterator[~Item]:
128    def copied(self) -> Iterator[Item]:
129        """Creates an iterator which `deeply` copies all of its elements.
130
131        .. warn::
132            This will `deeply` copy all of the elements, Use `Iterator.by_ref`
133            if you want copy of the iterator reference.
134
135        Example
136        -------
137        ```py
138        it = Iterator([None, None, None])
139        copied_iter = it.copied()
140        assert it.collect() == copied.collect()
141        ```
142        """
143        return Iterator(_copy.deepcopy(self._items))

Creates an iterator which deeply copies all of its elements.

.. warn:: This will deeply copy all of the elements, Use Iterator.by_ref if you want copy of the iterator reference.

Example
it = Iterator([None, None, None])
copied_iter = it.copied()
assert it.collect() == copied.collect()
def by_ref(self) -> Iterator[~Item]:
145    def by_ref(self) -> Iterator[Item]:
146        """Creates an iterator which doesn't consume its elements.
147        but instead shallow copy it.
148
149        Example
150        -------
151        ```py
152        it = Iterator([None, None, None])
153        for ref in it.by_ref():
154            ...
155
156        # Original not consumed.
157        assert it.count() == 3
158        ```
159        """
160        return Iterator(_copy.copy(self._items))

Creates an iterator which doesn't consume its elements. but instead shallow copy it.

Example
it = Iterator([None, None, None])
for ref in it.by_ref():
    ...

# Original not consumed.
assert it.count() == 3
def next(self) -> ~Item:
162    def next(self) -> Item:
163        """Returns the next item in the iterator.
164
165        Example
166        -------
167        ```py
168        iterator = Iterator(["1", "2", "3"])
169        item = iterator.next()
170        assert item == "1"
171        item = iterator.next()
172        assert item == "2"
173        ```
174
175        Raises
176        ------
177        `StopIteration`
178            If no elements are left in the iterator.
179        """
180        try:
181            return self.__next__()
182        except StopIteration:
183            self._ok()

Returns the next item in the iterator.

Example
iterator = Iterator(["1", "2", "3"])
item = iterator.next()
assert item == "1"
item = iterator.next()
assert item == "2"
Raises
  • StopIteration: If no elements are left in the iterator.
def map( self, predicate: 'collections.Callable[[Item], OtherItem]') -> 'Iterator[OtherItem]':
185    def map(
186        self, predicate: collections.Callable[[Item], OtherItem]
187    ) -> Iterator[OtherItem]:
188        """Maps each item in the iterator to its predicated value.
189
190        Example
191        -------
192        ```py
193        iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
194        print(iterator)
195        # <Iterator([1, 2, 3])>
196        ```
197
198        Parameters
199        ----------
200        predicate: `collections.Callable[[Item], OtherItem]`
201            The function to map each item in the iterator to its predicated value.
202
203        Returns
204        -------
205        `Iterator[OtherItem]`
206            The mapped iterator.
207
208        Raises
209        ------
210        `StopIteration`
211            If no elements are left in the iterator.
212        """
213        return Iterator(map(predicate, self._items))

Maps each item in the iterator to its predicated value.

Example
iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
print(iterator)
# <Iterator([1, 2, 3])>
Parameters
  • predicate (collections.Callable[[Item], OtherItem]): The function to map each item in the iterator to its predicated value.
Returns
  • Iterator[OtherItem]: The mapped iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def take(self, n: int) -> Iterator[~Item]:
215    def take(self, n: int) -> Iterator[Item]:
216        """Take the first number of items until the number of items are yielded or
217        the end of the iterator is reached.
218
219        Example
220        -------
221        ```py
222        iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
223        print(iterator.take(2))
224        # <Iterator([GameMode.RAID, GameMode.STRIKE])>
225        ```
226
227        Parameters
228        ----------
229        n: `int`
230            The number of items to take.
231
232        Raises
233        ------
234        `StopIteration`
235            If no elements are left in the iterator.
236        """
237        return Iterator(itertools.islice(self._items, n))

Take the first number of items until the number of items are yielded or the end of the iterator is reached.

Example
iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
print(iterator.take(2))
# <Iterator([GameMode.RAID, GameMode.STRIKE])>
Parameters
  • n (int): The number of items to take.
Raises
  • StopIteration: If no elements are left in the iterator.
def take_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> Iterator[~Item]:
239    def take_while(
240        self, predicate: collections.Callable[[Item], bool]
241    ) -> Iterator[Item]:
242        """Yields items from the iterator while predicate returns `True`.
243
244        Example
245        -------
246        ```py
247        iterator = Iterator([STEAM, XBOX, STADIA])
248        print(iterator.take_while(lambda platform: platform is not XBOX))
249        # <Iterator([STEAM])>
250        ```
251
252        Parameters
253        ----------
254        predicate: `collections.Callable[[Item], bool]`
255            The function to predicate each item in the iterator.
256
257        Raises
258        ------
259        `StopIteration`
260            If no elements are left in the iterator.
261        """
262        return Iterator(itertools.takewhile(predicate, self._items))

Yields items from the iterator while predicate returns True.

Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.take_while(lambda platform: platform is not XBOX))
# <Iterator([STEAM])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def drop_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> Iterator[~Item]:
264    def drop_while(
265        self, predicate: collections.Callable[[Item], bool]
266    ) -> Iterator[Item]:
267        """Yields items from the iterator while predicate returns `False`.
268
269        Example
270        -------
271        ```py
272        iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
273        print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
274        # <Iterator([DestinyMembership(name="Bob")])>
275        ```
276
277        Parameters
278        ----------
279        predicate: `collections.Callable[[Item], bool]`
280            The function to predicate each item in the iterator.
281
282        Raises
283        ------
284        `StopIteration`
285            If no elements are left in the iterator.
286        """
287        return Iterator(itertools.dropwhile(predicate, self._items))

Yields items from the iterator while predicate returns False.

Example
iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
# <Iterator([DestinyMembership(name="Bob")])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def filter( self, predicate: collections.abc.Callable[[~Item], bool]) -> Iterator[~Item]:
289    def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]:
290        """Filters the iterator to only yield items that match the predicate.
291
292        Example
293        -------
294        ```py
295        names = Iterator(["Jim", "Bob", "Mike", "Jess"])
296        print(names.filter(lambda n: n != "Jim"))
297        # <Iterator(["Bob", "Mike", "Jess"])>
298        ```
299        """
300        return Iterator(filter(predicate, self._items))

Filters the iterator to only yield items that match the predicate.

Example
names = Iterator(["Jim", "Bob", "Mike", "Jess"])
print(names.filter(lambda n: n != "Jim"))
# <Iterator(["Bob", "Mike", "Jess"])>
def skip(self, n: int) -> Iterator[~Item]:
302    def skip(self, n: int) -> Iterator[Item]:
303        """Skips the first number of items in the iterator.
304
305        Example
306        -------
307        ```py
308        iterator = Iterator([STEAM, XBOX, STADIA])
309        print(iterator.skip(1))
310        # <Iterator([XBOX, STADIA])>
311        ```
312        """
313        return Iterator(itertools.islice(self._items, n, None))

Skips the first number of items in the iterator.

Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.skip(1))
# <Iterator([XBOX, STADIA])>
def zip(self, other: 'Iterator[OtherItem]') -> 'Iterator[tuple[Item, OtherItem]]':
315    def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]:
316        """Zips the iterator with another iterable.
317
318        Example
319        -------
320        ```py
321        iterator = Iterator([1, 3, 5])
322        other = Iterator([2, 4, 6])
323        for item, other_item in iterator.zip(other):
324            print(item, other_item)
325        # <Iterator([(1, 2), (3, 4), (5, 6)])>
326        ```
327
328        Parameters
329        ----------
330        other: `Iterator[OtherItem]`
331            The iterable to zip with.
332
333        Raises
334        ------
335        `StopIteration`
336            If no elements are left in the iterator.
337        """
338        return Iterator(zip(self._items, other))

Zips the iterator with another iterable.

Example
iterator = Iterator([1, 3, 5])
other = Iterator([2, 4, 6])
for item, other_item in iterator.zip(other):
    print(item, other_item)
# <Iterator([(1, 2), (3, 4), (5, 6)])>
Parameters
  • other (Iterator[OtherItem]): The iterable to zip with.
Raises
  • StopIteration: If no elements are left in the iterator.
def all(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
340    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
341        """`True` if all items in the iterator match the predicate.
342
343        Example
344        -------
345        ```py
346        iterator = Iterator([1, 2, 3])
347        while iterator.all(lambda item: isinstance(item, int)):
348            print("Still all integers")
349            continue
350        # Still all integers
351        ```
352
353        Parameters
354        ----------
355        predicate: `collections.Callable[[Item], bool]`
356            The function to test each item in the iterator.
357
358        Raises
359        ------
360        `StopIteration`
361            If no elements are left in the iterator.
362        """
363        return all(predicate(item) for item in self)

True if all items in the iterator match the predicate.

Example
iterator = Iterator([1, 2, 3])
while iterator.all(lambda item: isinstance(item, int)):
    print("Still all integers")
    continue
# Still all integers
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def any(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
365    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
366        """`True` if any items in the iterator match the predicate.
367
368        Example
369        -------
370        ```py
371        iterator = Iterator([1, 2, 3])
372        if iterator.any(lambda item: isinstance(item, int)):
373            print("At least one item is an int.")
374        # At least one item is an int.
375        ```
376
377        Parameters
378        ----------
379        predicate: `collections.Callable[[Item], bool]`
380            The function to test each item in the iterator.
381
382        Raises
383        ------
384        `StopIteration`
385            If no elements are left in the iterator.
386        """
387        return any(predicate(item) for item in self)

True if any items in the iterator match the predicate.

Example
iterator = Iterator([1, 2, 3])
if iterator.any(lambda item: isinstance(item, int)):
    print("At least one item is an int.")
# At least one item is an int.
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def sort( self, *, key: 'collections.Callable[[Item], typeshed.SupportsRichComparison]', reverse: bool = False) -> Iterator[~Item]:
389    def sort(
390        self,
391        *,
392        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
393        reverse: bool = False,
394    ) -> Iterator[Item]:
395        """Sorts the iterator.
396
397        Example
398        -------
399        ```py
400        iterator = Iterator([3, 1, 6, 7])
401        print(iterator.sort(key=lambda item: item))
402        # <Iterator([1, 3, 6, 7])>
403        ```
404
405        Parameters
406        ----------
407        key: `collections.Callable[[Item], Any]`
408            The function to sort by.
409        reverse: `bool`
410            Whether to reverse the sort.
411
412        Raises
413        ------
414        `StopIteration`
415            If no elements are left in the iterator.
416        """
417        return Iterator(sorted(self._items, key=key, reverse=reverse))

Sorts the iterator.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.sort(key=lambda item: item))
# <Iterator([1, 3, 6, 7])>
Parameters
  • key (collections.Callable[[Item], Any]): The function to sort by.
  • reverse (bool): Whether to reverse the sort.
Raises
  • StopIteration: If no elements are left in the iterator.
def first(self) -> ~Item:
419    def first(self) -> Item:
420        """Returns the first item in the iterator.
421
422        Example
423        -------
424        ```py
425        iterator = Iterator([3, 1, 6, 7])
426        print(iterator.first())
427        3
428        ```
429
430        Raises
431        ------
432        `StopIteration`
433            If no elements are left in the iterator.
434        """
435        return self.take(1).next()

Returns the first item in the iterator.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.first())
3
Raises
  • StopIteration: If no elements are left in the iterator.
def last(self) -> ~Item:
437    def last(self) -> Item:
438        """Returns the last item in the iterator.
439
440        Example
441        ------
442        ```py
443        it = Iterator((1, 2, 3))
444        assert it.first() == 1 and it.last() == 3
445        ```
446        """
447        return self.reversed().first()

Returns the last item in the iterator.

Example
it = Iterator((1, 2, 3))
assert it.first() == 1 and it.last() == 3
def reversed(self) -> Iterator[~Item]:
449    def reversed(self) -> Iterator[Item]:
450        """Returns a new iterator that yields the items in the iterator in reverse order.
451
452        Example
453        -------
454        ```py
455        iterator = Iterator([3, 1, 6, 7])
456        print(iterator.reversed())
457        # <Iterator([7, 6, 1, 3])>
458        ```
459
460        Raises
461        ------
462        `StopIteration`
463            If no elements are left in the iterator.
464        """
465        return Iterator(reversed(self.collect()))

Returns a new iterator that yields the items in the iterator in reverse order.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.reversed())
# <Iterator([7, 6, 1, 3])>
Raises
  • StopIteration: If no elements are left in the iterator.
def count(self) -> int:
467    def count(self) -> int:
468        """Returns the number of items in the iterator.
469
470        Example
471        -------
472        ```py
473        iterator = Iterator([3, 1, 6, 7])
474        print(iterator.count())
475        4
476        ```
477        """
478        count = 0
479        for _ in self:
480            count += 1
481
482        return count

Returns the number of items in the iterator.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.count())
4
def union( self, other: Iterator[~Item]) -> Iterator[~Item]:
484    def union(self, other: Iterator[Item]) -> Iterator[Item]:
485        """Returns a new iterator that yields all items from both iterators.
486
487        Example
488        -------
489        ```py
490        iterator = Iterator([1, 2, 3])
491        other = Iterator([4, 5, 6])
492        print(iterator.union(other))
493        # <Iterator([1, 2, 3, 4, 5, 6])>
494        ```
495
496        Parameters
497        ----------
498        other: `Iterator[Item]`
499            The iterable to union with.
500
501        Raises
502        ------
503        `StopIteration`
504            If no elements are left in the iterator.
505        """
506        return Iterator(itertools.chain(self._items, other))

Returns a new iterator that yields all items from both iterators.

Example
iterator = Iterator([1, 2, 3])
other = Iterator([4, 5, 6])
print(iterator.union(other))
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
  • other (Iterator[Item]): The iterable to union with.
Raises
  • StopIteration: If no elements are left in the iterator.
def for_each(self, func: collections.abc.Callable[[~Item], typing.Any]) -> None:
508    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
509        """Calls the function on each item in the iterator.
510
511        Example
512        -------
513        ```py
514        iterator = Iterator([1, 2, 3])
515        iterator.for_each(lambda item: print(item))
516        # 1
517        # 2
518        # 3
519        ```
520
521        Parameters
522        ----------
523        func: `typeshed.Callable[[Item], None]`
524            The function to call on each item in the iterator.
525        """
526        for item in self:
527            func(item)

Calls the function on each item in the iterator.

Example
iterator = Iterator([1, 2, 3])
iterator.for_each(lambda item: print(item))
# 1
# 2
# 3
Parameters
  • func (typeshed.Callable[[Item], None]): The function to call on each item in the iterator.
async def async_for_each( self, func: collections.abc.Callable[[~Item], collections.abc.Coroutine[None, None, None]]) -> None:
529    async def async_for_each(
530        self,
531        func: collections.Callable[[Item], collections.Coroutine[None, None, None]],
532    ) -> None:
533        """Calls the async function on each item in the iterator concurrently.
534
535        Example
536        -------
537        ```py
538        async def signup(username: str) -> None:
539            async with aiohttp.request('POST', '...') as r:
540                # Actual logic.
541                ...
542
543        async def main():
544            users = aiobungie.into_iter(["user_danny", "user_jojo"])
545            await users.async_for_each(lambda username: signup(username))
546        ```
547
548        Parameters
549        ----------
550        func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]`
551            The async function to call on each item in the iterator.
552        """
553        await _helpers.awaits(*(func(item) for item in self))

Calls the async function on each item in the iterator concurrently.

Example
async def signup(username: str) -> None:
    async with aiohttp.request('POST', '...') as r:
        # Actual logic.
        ...

async def main():
    users = aiobungie.into_iter(["user_danny", "user_jojo"])
    await users.async_for_each(lambda username: signup(username))
Parameters
  • func (collections.Callable[[Item], collections.Coroutine[None, None, None]]): The async function to call on each item in the iterator.
def enumerate( self, *, start: int = 0) -> Iterator[tuple[int, ~Item]]:
555    def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]:
556        """Returns a new iterator that yields tuples of the index and item.
557
558        Example
559        -------
560        ```py
561        iterator = Iterator([1, 2, 3])
562        for index, item in iterator.enumerate():
563            print(index, item)
564        # 0 1
565        # 1 2
566        # 2 3
567        ```
568
569        Raises
570        ------
571        `StopIteration`
572            If no elements are left in the iterator.
573        """
574        return Iterator(enumerate(self._items, start=start))

Returns a new iterator that yields tuples of the index and item.

Example
iterator = Iterator([1, 2, 3])
for index, item in iterator.enumerate():
    print(index, item)
# 0 1
# 1 2
# 2 3
Raises
  • StopIteration: If no elements are left in the iterator.
@typing.final
class MembershipOption(builtins.int, aiobungie.Enum):
702@typing.final
703class MembershipOption(int, Enum):
704    """A enum for GroupV2 membership options."""
705
706    REVIEWD = 0
707    OPEN = 1
708    CLOSED = 2

A enum for GroupV2 membership options.

REVIEWD = <MembershipOption.REVIEWD: 0>
OPEN = <MembershipOption.OPEN: 1>
CLOSED = <MembershipOption.CLOSED: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class MembershipType(builtins.int, aiobungie.Enum):
450@typing.final
451class MembershipType(int, Enum):
452    """An Enum for Bungie membership types."""
453
454    NONE = 0
455    XBOX = 1
456    PSN = 2
457    STEAM = 3
458    BLIZZARD = 4
459    STADIA = 5
460    EPIC_GAMES_STORE = 6
461    DEMON = 10
462    BUNGIE = 254
463    ALL = -1

An Enum for Bungie membership types.

NONE = <MembershipType.NONE: 0>
XBOX = <MembershipType.XBOX: 1>
PSN = <MembershipType.PSN: 2>
STEAM = <MembershipType.STEAM: 3>
BLIZZARD = <MembershipType.BLIZZARD: 4>
STADIA = <MembershipType.STADIA: 5>
EPIC_GAMES_STORE = <MembershipType.EPIC_GAMES_STORE: 6>
DEMON = <MembershipType.DEMON: 10>
BUNGIE = <MembershipType.BUNGIE: 254>
ALL = <MembershipType.ALL: -1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class MembershipTypeError(aiobungie.BadRequest):
181@attrs.define(auto_exc=True)
182class MembershipTypeError(BadRequest):
183    """A bad request error raised when passing wrong membership to the request.
184
185    Those fields are useful since it returns the correct membership and id which can be used
186    to make the request again with those fields.
187
188    Example
189    -------
190    ```py
191    try:
192        profile = await client.fetch_profile(
193            member_id=1,
194            type=aiobungie.MembershipType.STADIA,
195            components=()
196        )
197
198    # Membership type is wrong!
199    except aiobungie.MembershipTypeError as err:
200        correct_membership = err.into_membership()
201        profile_id = err.membership_id
202
203        # Recall the method.
204        profile = await client.fetch_profile(
205            member_id=profile_id,
206            type=correct_membership,
207            components=()
208        )
209    ```
210    """
211
212    membership_type: str
213    """The errored membership type passed to the request."""
214
215    membership_id: int
216    """The errored user's membership id."""
217
218    required_membership: str
219    """The required correct membership for errored user."""
220
221    def into_membership(self, value: str | None = None) -> enums.MembershipType:
222        """Turn the required membership from `str` into `aiobungie.Membership` type.
223
224        If value parameter is not provided it will fall back to the required membership.
225        """
226        if value is None:
227            return _MEMBERSHIP_LOOKUP[self.required_membership]
228        return _MEMBERSHIP_LOOKUP[value]
229
230    def __str__(self) -> str:
231        return (
232            f"Expected membership: {self.into_membership().name.replace('_', '').title()}, "
233            f"But got {self.into_membership(self.membership_type)} for id {self.membership_id}"
234        )
235
236    def __int__(self) -> int:
237        return int(self.membership_id)

A bad request error raised when passing wrong membership to the request.

Those fields are useful since it returns the correct membership and id which can be used to make the request again with those fields.

Example
try:
    profile = await client.fetch_profile(
        member_id=1,
        type=aiobungie.MembershipType.STADIA,
        components=()
    )

# Membership type is wrong!
except aiobungie.MembershipTypeError as err:
    correct_membership = err.into_membership()
    profile_id = err.membership_id

    # Recall the method.
    profile = await client.fetch_profile(
        member_id=profile_id,
        type=correct_membership,
        components=()
    )
MembershipTypeError( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], membership_type: str, membership_id: int, required_membership: str)
 2def __init__(self, message, url, body, headers, membership_type, membership_id, required_membership):
 3    self.message = message
 4    self.url = url
 5    self.body = body
 6    self.headers = headers
 7    self.http_status = attr_dict['http_status'].default
 8    self.membership_type = membership_type
 9    self.membership_id = membership_id
10    self.required_membership = required_membership
11    BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.membership_type,self.membership_id,self.required_membership)

Method generated by attrs for class MembershipTypeError.

membership_type: str

The errored membership type passed to the request.

membership_id: int

The errored user's membership id.

required_membership: str

The required correct membership for errored user.

def into_membership( self, value: str | None = None) -> MembershipType:
221    def into_membership(self, value: str | None = None) -> enums.MembershipType:
222        """Turn the required membership from `str` into `aiobungie.Membership` type.
223
224        If value parameter is not provided it will fall back to the required membership.
225        """
226        if value is None:
227            return _MEMBERSHIP_LOOKUP[self.required_membership]
228        return _MEMBERSHIP_LOOKUP[value]

Turn the required membership from str into aiobungie.Membership type.

If value parameter is not provided it will fall back to the required membership.

Inherited Members
BadRequest
url
body
headers
http_status
HTTPError
message
builtins.BaseException
with_traceback
add_note
args
@typing.final
class MilestoneType(builtins.int, aiobungie.Enum):
495@typing.final
496class MilestoneType(int, Enum):
497    """An Enum for Destiny 2 milestone types."""
498
499    UNKNOWN = 0
500    TUTORIAL = 1
501    ONETIME = 2
502    WEEKLY = 3
503    DAILY = 4
504    SPECIAL = 5

An Enum for Destiny 2 milestone types.

UNKNOWN = <MilestoneType.UNKNOWN: 0>
TUTORIAL = <MilestoneType.TUTORIAL: 1>
ONETIME = <MilestoneType.ONETIME: 2>
WEEKLY = <MilestoneType.WEEKLY: 3>
DAILY = <MilestoneType.DAILY: 4>
SPECIAL = <MilestoneType.SPECIAL: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class NotFound(aiobungie.HTTPException):
145@attrs.define(auto_exc=True)
146class NotFound(HTTPException):
147    """Raised when an unknown resource was not found."""
148
149    http_status: http.HTTPStatus = attrs.field(
150        default=http.HTTPStatus.NOT_FOUND, init=False
151    )

Raised when an unknown resource was not found.

NotFound( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class NotFound.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
add_note
args
@typing.final
class ObjectiveUIStyle(builtins.int, aiobungie.Enum):
 93@typing.final
 94class ObjectiveUIStyle(int, enums.Enum):
 95    NONE = 0
 96    HIGHLIGHTED = 1
 97    CRAFTING_WEAPON_LEVEL = 2
 98    CRAFTING_WEAPON_LEVEL_PROGRESS = 3
 99    CRAFTING_WEAPON_TIMESTAMP = 4
100    CRAFTING_MEMENTOS = 5
101    CRAFTING_MEMENTO_TITLE = 6

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by '+' or '-' and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal.

>>> int('0b100', base=0)
4
NONE = <ObjectiveUIStyle.NONE: 0>
HIGHLIGHTED = <ObjectiveUIStyle.HIGHLIGHTED: 1>
CRAFTING_WEAPON_LEVEL = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL: 2>
CRAFTING_WEAPON_LEVEL_PROGRESS = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL_PROGRESS: 3>
CRAFTING_WEAPON_TIMESTAMP = <ObjectiveUIStyle.CRAFTING_WEAPON_TIMESTAMP: 4>
CRAFTING_MEMENTOS = <ObjectiveUIStyle.CRAFTING_MEMENTOS: 5>
CRAFTING_MEMENTO_TITLE = <ObjectiveUIStyle.CRAFTING_MEMENTO_TITLE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Place(builtins.int, aiobungie.Enum):
219@typing.final
220class Place(int, Enum):
221    """An Enum for Destiny 2 Places and NOT Planets"""
222
223    ORBIT = 2961497387
224    SOCIAL = 4151112093
225    LIGHT_HOUSE = 4276116472
226    EXPLORE = 3497767639

An Enum for Destiny 2 Places and NOT Planets

ORBIT = <Place.ORBIT: 2961497387>
SOCIAL = <Place.SOCIAL: 4151112093>
LIGHT_HOUSE = <Place.LIGHT_HOUSE: 4276116472>
EXPLORE = <Place.EXPLORE: 3497767639>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Planet(builtins.int, aiobungie.Enum):
184@typing.final
185class Planet(int, Enum):
186    """An Enum for all available planets in Destiny 2."""
187
188    UNKNOWN = 0
189    """Unknown space"""
190
191    EARTH = 3747705955
192    """Earth"""
193
194    DREAMING_CITY = 2877881518
195    """The Dreaming city."""
196
197    NESSUS = 3526908984
198    """Nessus"""
199
200    MOON = 3325508439
201    """The Moon"""
202
203    COSMODROME = 3990611421
204    """The Cosmodrome"""
205
206    TANGLED_SHORE = 3821439926
207    """The Tangled Shore"""
208
209    VENUS = 3871070152
210    """Venus"""
211
212    EAZ = 541863059  # Exclusive event.
213    """European Aerial Zone"""
214
215    EUROPA = 1729879943
216    """Europa"""

An Enum for all available planets in Destiny 2.

UNKNOWN = <Planet.UNKNOWN: 0>

Unknown space

EARTH = <Planet.EARTH: 3747705955>

Earth

DREAMING_CITY = <Planet.DREAMING_CITY: 2877881518>

The Dreaming city.

NESSUS = <Planet.NESSUS: 3526908984>

Nessus

MOON = <Planet.MOON: 3325508439>

The Moon

COSMODROME = <Planet.COSMODROME: 3990611421>

The Cosmodrome

TANGLED_SHORE = <Planet.TANGLED_SHORE: 3821439926>

The Tangled Shore

VENUS = <Planet.VENUS: 3871070152>

Venus

EAZ = <Planet.EAZ: 541863059>

European Aerial Zone

EUROPA = <Planet.EUROPA: 1729879943>

Europa

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Presence(builtins.int, aiobungie.Enum):
672@typing.final
673class Presence(int, Enum):
674    """An enum for a bungie friend status."""
675
676    OFFLINE_OR_UNKNOWN = 0
677    ONLINE = 1

An enum for a bungie friend status.

OFFLINE_OR_UNKNOWN = <Presence.OFFLINE_OR_UNKNOWN: 0>
ONLINE = <Presence.ONLINE: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class PrivacySetting(builtins.int, aiobungie.Enum):
760@typing.final
761class PrivacySetting(int, Enum):
762    """An enum for players's privacy settings."""
763
764    OPEN = 0
765    CLAN_AND_FRIENDS = 1
766    FRIENDS_ONLY = 2
767    INVITE_ONLY = 3
768    CLOSED = 4

An enum for players's privacy settings.

OPEN = <PrivacySetting.OPEN: 0>
CLAN_AND_FRIENDS = <PrivacySetting.CLAN_AND_FRIENDS: 1>
FRIENDS_ONLY = <PrivacySetting.FRIENDS_ONLY: 2>
INVITE_ONLY = <PrivacySetting.INVITE_ONLY: 3>
CLOSED = <PrivacySetting.CLOSED: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
class RESTClient(aiobungie.interfaces.rest.RESTInterface):
 310class RESTClient(interfaces.RESTInterface):
 311    """A single process REST client implementation.
 312
 313    This client is designed to only make HTTP requests and return raw JSON objects.
 314
 315    Example
 316    -------
 317    ```py
 318    import aiobungie
 319
 320    client = aiobungie.RESTClient("TOKEN")
 321    async with client:
 322        response = await client.fetch_clan_members(4389205)
 323        for member in response['results']:
 324            print(member['destinyUserInfo'])
 325    ```
 326
 327    Parameters
 328    ----------
 329    token : `str`
 330        A valid application token from Bungie's developer portal.
 331
 332    Other Parameters
 333    ----------------
 334    max_retries : `int`
 335        The max retries number to retry if the request hit a `5xx` status code.
 336    client_secret : `str | None`
 337        An optional application client secret,
 338        This is only needed if you're fetching OAuth2 tokens with this client.
 339    client_id : `int | None`
 340        An optional application client id,
 341        This is only needed if you're fetching OAuth2 tokens with this client.
 342    debug : `bool | str`
 343        Whether to enable logging responses or not.
 344
 345    Logging Levels
 346    --------------
 347    * `False`: This will disable logging.
 348    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
 349    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
 350    """
 351
 352    __slots__ = (
 353        "_token",
 354        "_session",
 355        "_lock",
 356        "_max_retries",
 357        "_client_secret",
 358        "_client_id",
 359        "_metadata",
 360        "_dumps",
 361        "_loads",
 362    )
 363
 364    def __init__(
 365        self,
 366        token: str,
 367        /,
 368        *,
 369        client_secret: str | None = None,
 370        client_id: int | None = None,
 371        client_session: aiohttp.ClientSession | None = None,
 372        dumps: typedefs.Dumps = helpers.dumps,
 373        loads: typedefs.Loads = helpers.loads,
 374        max_retries: int = 4,
 375        debug: typing.Literal["TRACE"] | bool | int = False,
 376    ) -> None:
 377        self._session = client_session
 378        self._lock: asyncio.Lock | None = None
 379        self._client_secret = client_secret
 380        self._client_id = client_id
 381        self._token: str = token
 382        self._max_retries = max_retries
 383        self._dumps = dumps
 384        self._loads = loads
 385        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
 386        self.with_debug(debug)
 387
 388    @property
 389    def client_id(self) -> int | None:
 390        return self._client_id
 391
 392    @property
 393    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 394        return self._metadata
 395
 396    @property
 397    def is_alive(self) -> bool:
 398        return self._session is not None
 399
 400    @typing.final
 401    async def close(self) -> None:
 402        if self._session is None:
 403            raise RuntimeError("REST client is not running.")
 404
 405        await self._session.close()
 406        self._session = None
 407
 408    @typing.final
 409    def open(self) -> None:
 410        """Open a new client session. This is called internally with contextmanager usage."""
 411        if self._session:
 412            raise RuntimeError("Cannot open REST client when it's already open.")
 413
 414        self._session = aiohttp.ClientSession(
 415            connector=aiohttp.TCPConnector(),
 416            connector_owner=True,
 417            raise_for_status=False,
 418            timeout=aiohttp.ClientTimeout(total=30.0),
 419        )
 420
 421    @typing.final
 422    async def static_request(
 423        self,
 424        method: _HTTP_METHOD,
 425        path: str,
 426        *,
 427        auth: str | None = None,
 428        json: collections.Mapping[str, typing.Any] | None = None,
 429    ) -> typedefs.JSONIsh:
 430        return await self._request(method, path, auth=auth, json=json)
 431
 432    @typing.overload
 433    def build_oauth2_url(self, client_id: int) -> builders.OAuthURL: ...
 434
 435    @typing.overload
 436    def build_oauth2_url(self) -> builders.OAuthURL | None: ...
 437
 438    @typing.final
 439    def build_oauth2_url(
 440        self, client_id: int | None = None
 441    ) -> builders.OAuthURL | None:
 442        client_id = client_id or self._client_id
 443        if client_id is None:
 444            return None
 445
 446        return builders.OAuthURL(client_id=client_id)
 447
 448    @typing.final
 449    def with_debug(
 450        self,
 451        level: typing.Literal["TRACE"] | bool | int = True,
 452        file: str | pathlib.Path | None = None,
 453    ) -> None:
 454        """Enable debugging for this client with a level. Defaults to `True`.
 455
 456        Parameters
 457        ----------
 458        level: `NotRequired[int | bool | typing.Literal["TRACE"] | None]`
 459            The level of the logger. This field is not required.
 460        file: `pathlib.Path | str | None`
 461            An optional file to write the logs into.
 462
 463        Logging Levels
 464        --------------
 465        * `False`: This will disable logging.
 466        * `True`: This will set the level to `DEBUG` and enable logging minimal information.
 467        * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
 468        """
 469        logging.logThreads = False
 470        logging.logMultiprocessing = False
 471        logging.logProcesses = False
 472        logging.captureWarnings(True)
 473
 474        format = "%(levelname)s " "%(asctime)23.23s " "%(name)s: " "%(message)s"
 475
 476        file_handler = (logging.FileHandler(file),) if file else None
 477        if level == "TRACE" or level == TRACE:
 478            logging.basicConfig(
 479                level=TRACE, format=format, stream=sys.stdout, handlers=file_handler
 480            )
 481
 482        elif level is True:
 483            logging.basicConfig(
 484                level=logging.DEBUG,
 485                format=format,
 486                stream=sys.stdout,
 487                handlers=file_handler,
 488            )
 489
 490    async def _request(
 491        self,
 492        method: _HTTP_METHOD,
 493        route: str,
 494        *,
 495        base: bool = False,
 496        oauth2: bool = False,
 497        auth: str | None = None,
 498        unwrap_bytes: bool = False,
 499        json: collections.Mapping[str, typing.Any] | None = None,
 500        data: collections.Mapping[str, typing.Any] | None = None,
 501        params: collections.Mapping[str, typing.Any] | None = None,
 502    ) -> typedefs.JSONIsh:
 503        # This is not None when opening the client.
 504        assert self._session is not None
 505
 506        retries: int = 0
 507        headers: collections.MutableMapping[str, typing.Any] = {}
 508
 509        headers[_USER_AGENT_HEADERS] = _USER_AGENT
 510        headers["X-API-KEY"] = self._token
 511
 512        if auth is not None:
 513            headers[_AUTH_HEADER] = f"Bearer {auth}"
 514
 515        # Handling endpoints
 516        endpoint = url.BASE
 517
 518        if not base:
 519            endpoint = endpoint + url.REST_EP
 520
 521        if oauth2:
 522            assert self._client_id
 523            assert self._client_secret
 524            headers["client_secret"] = self._client_secret
 525
 526            headers["Content-Type"] = "application/x-www-form-urlencoded"
 527            endpoint = endpoint + url.TOKEN_EP
 528
 529        if self._lock is None:
 530            self._lock = asyncio.Lock()
 531
 532        if json:
 533            headers["Content-Type"] = _APP_JSON
 534
 535        stack = contextlib.AsyncExitStack()
 536        while True:
 537            try:
 538                await stack.enter_async_context(self._lock)
 539
 540                # We make the request here.
 541                taken_time = time.monotonic()
 542                response = await self._session.request(
 543                    method=method,
 544                    url=f"{endpoint}/{route}",
 545                    headers=headers,
 546                    data=_JSONPayload(json) if json else data,
 547                    params=params,
 548                )
 549                response_time = (time.monotonic() - taken_time) * 1_000
 550
 551                _LOGGER.debug(
 552                    "%s %s %s Time %.4fms",
 553                    method,
 554                    f"{endpoint}/{route}",
 555                    f"{response.status} {response.reason}",
 556                    response_time,
 557                )
 558
 559                await self._handle_ratelimit(response, method, route)
 560
 561            except aiohttp.ClientConnectionError as exc:
 562                if retries >= self._max_retries:
 563                    raise error.HTTPError(
 564                        str(exc),
 565                        http.HTTPStatus.SERVICE_UNAVAILABLE,
 566                    )
 567                backoff_ = backoff.ExponentialBackOff(maximum=8)
 568
 569                timer = next(backoff_)
 570                _LOGGER.warning(
 571                    "Client received a connection error <%s> Retrying in %.2fs. Remaining retries: %s",
 572                    type(exc).__qualname__,
 573                    timer,
 574                    self._max_retries - retries,
 575                )
 576                retries += 1
 577                await asyncio.sleep(timer)
 578                continue
 579
 580            finally:
 581                await stack.aclose()
 582
 583            if response.status == http.HTTPStatus.NO_CONTENT:
 584                return None
 585
 586            # Handle the successful response.
 587            if 300 > response.status >= 200:
 588                if unwrap_bytes:
 589                    # We need to read the bytes for the manifest response.
 590                    return await response.read()
 591
 592                # Bungie get funky and return HTML instead of JSON when making an authorized
 593                # request with a dummy access token. We could technically read the page content
 594                # but that's Bungie's fault for not returning a JSON response.
 595                if response.content_type != _APP_JSON:
 596                    raise error.HTTPError(
 597                        message=f"Expected JSON response, Got {response.content_type}, "
 598                        f"{response.real_url.human_repr()}",
 599                        http_status=http.HTTPStatus(response.status),
 600                    )
 601
 602                json_data = self._loads(await response.read())
 603
 604                _LOGGER.debug(
 605                    "%s %s %s Time %.4fms",
 606                    method,
 607                    f"{endpoint}/{route}",
 608                    f"{response.status} {response.reason}",
 609                    response_time,
 610                )
 611
 612                if _LOGGER.isEnabledFor(TRACE):
 613                    _LOGGER.log(
 614                        TRACE,
 615                        "%s",
 616                        error.stringify_headers(dict(response.headers)),
 617                    )
 618
 619                    details: collections.MutableMapping[str, typing.Any] = {}
 620                    if json:
 621                        details["json"] = json
 622
 623                    if data:
 624                        details["data"] = data
 625
 626                    if params:
 627                        details["params"] = params
 628
 629                    if details:
 630                        _LOGGER.log(TRACE, "%s", error.stringify_headers(details))
 631
 632                # Return the response.
 633                # auth responses are not inside a Response object.
 634                if oauth2:
 635                    return json_data
 636
 637                # The reason we have a type ignore is because the actual response type
 638                # is within this `Response` key.
 639                return json_data["Response"]  # type: ignore
 640
 641            if (
 642                response.status in _RETRY_5XX and retries < self._max_retries  # noqa: W503
 643            ):
 644                backoff_ = backoff.ExponentialBackOff(maximum=6)
 645                sleep_time = next(backoff_)
 646                _LOGGER.warning(
 647                    "Got %i - %s. Sleeping for %.2f seconds. Remaining retries: %i",
 648                    response.status,
 649                    response.reason,
 650                    sleep_time,
 651                    self._max_retries - retries,
 652                )
 653
 654                retries += 1
 655                await asyncio.sleep(sleep_time)
 656                continue
 657
 658            raise await error.panic(response)
 659
 660    async def __aenter__(self) -> RESTClient:
 661        self.open()
 662        return self
 663
 664    async def __aexit__(
 665        self,
 666        exception_type: type[BaseException] | None,
 667        exception: BaseException | None,
 668        exception_traceback: types.TracebackType | None,
 669    ) -> None:
 670        await self.close()
 671
 672    # We don't want this to be super complicated.
 673    @typing.final
 674    async def _handle_ratelimit(
 675        self,
 676        response: aiohttp.ClientResponse,
 677        method: str,
 678        route: str,
 679    ) -> None:
 680        if response.status != http.HTTPStatus.TOO_MANY_REQUESTS:
 681            return
 682
 683        if response.content_type != _APP_JSON:
 684            raise error.HTTPError(
 685                f"Being ratelimited on non JSON request, {response.content_type}.",
 686                http.HTTPStatus.TOO_MANY_REQUESTS,
 687            )
 688
 689        # The reason we have a type ignore here is that we guaranteed the content type is JSON above.
 690        json: typedefs.JSONObject = self._loads(await response.read())  # type: ignore
 691        retry_after = float(json.get("ThrottleSeconds", 15.0)) + 0.1
 692        max_calls: int = 0
 693
 694        while True:
 695            if max_calls == 10:
 696                # Max retries by default. We raise an error here.
 697                raise error.RateLimitedError(
 698                    body=json,
 699                    url=str(response.real_url),
 700                    retry_after=retry_after,
 701                )
 702
 703            # We sleep for a little bit to avoid funky behavior.
 704            _LOGGER.warning(
 705                "We're being ratelimited, Method %s Route %s. Sleeping for %.2fs.",
 706                method,
 707                route,
 708                retry_after,
 709            )
 710            await asyncio.sleep(retry_after)
 711            max_calls += 1
 712            continue
 713
 714    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
 715        data = {
 716            "grant_type": "authorization_code",
 717            "code": code,
 718            "client_id": self._client_id,
 719            "client_secret": self._client_secret,
 720        }
 721
 722        response = await self._request(_POST, "", data=data, oauth2=True)
 723        assert isinstance(response, dict)
 724        return builders.OAuth2Response.build_response(response)
 725
 726    async def refresh_access_token(
 727        self, refresh_token: str, /
 728    ) -> builders.OAuth2Response:
 729        data = {
 730            "grant_type": "refresh_token",
 731            "refresh_token": refresh_token,
 732            "client_id": self._client_id,
 733            "client_secret": self._client_secret,
 734        }
 735
 736        response = await self._request(_POST, "", data=data, oauth2=True)
 737        assert isinstance(response, dict)
 738        return builders.OAuth2Response.build_response(response)
 739
 740    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
 741        resp = await self._request(_GET, f"User/GetBungieNetUserById/{id}/")
 742        assert isinstance(resp, dict)
 743        return resp
 744
 745    async def fetch_user_themes(self) -> typedefs.JSONArray:
 746        resp = await self._request(_GET, "User/GetAvailableThemes/")
 747        assert isinstance(resp, list)
 748        return resp
 749
 750    async def fetch_membership_from_id(
 751        self,
 752        id: int,
 753        type: enums.MembershipType | int = enums.MembershipType.NONE,
 754        /,
 755    ) -> typedefs.JSONObject:
 756        resp = await self._request(_GET, f"User/GetMembershipsById/{id}/{int(type)}")
 757        assert isinstance(resp, dict)
 758        return resp
 759
 760    async def fetch_membership(
 761        self,
 762        name: str,
 763        code: int,
 764        type: enums.MembershipType | int = enums.MembershipType.ALL,
 765        /,
 766    ) -> typedefs.JSONArray:
 767        resp = await self._request(
 768            _POST,
 769            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
 770            json={"displayName": name, "displayNameCode": code},
 771        )
 772        assert isinstance(resp, list)
 773        return resp
 774
 775    async def search_users(self, name: str, /) -> typedefs.JSONObject:
 776        resp = await self._request(
 777            _POST,
 778            "User/Search/GlobalName/0",
 779            json={"displayNamePrefix": name},
 780        )
 781        assert isinstance(resp, dict)
 782        return resp
 783
 784    async def fetch_clan_from_id(
 785        self, id: int, /, access_token: str | None = None
 786    ) -> typedefs.JSONObject:
 787        resp = await self._request(_GET, f"GroupV2/{id}", auth=access_token)
 788        assert isinstance(resp, dict)
 789        return resp
 790
 791    async def fetch_clan(
 792        self,
 793        name: str,
 794        /,
 795        access_token: str | None = None,
 796        *,
 797        type: enums.GroupType | int = enums.GroupType.CLAN,
 798    ) -> typedefs.JSONObject:
 799        resp = await self._request(
 800            _GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
 801        )
 802        assert isinstance(resp, dict)
 803        return resp
 804
 805    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
 806        resp = await self._request(_GET, f"GroupV2/{clan_id}/AdminsAndFounder/")
 807        assert isinstance(resp, dict)
 808        return resp
 809
 810    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
 811        resp = await self._request(_GET, f"GroupV2/{clan_id}/OptionalConversations/")
 812        assert isinstance(resp, list)
 813        return resp
 814
 815    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
 816        resp = await self._request(_GET, f"App/Application/{appid}")
 817        assert isinstance(resp, dict)
 818        return resp
 819
 820    async def fetch_character(
 821        self,
 822        member_id: int,
 823        membership_type: enums.MembershipType | int,
 824        character_id: int,
 825        components: collections.Sequence[enums.ComponentType],
 826        auth: str | None = None,
 827    ) -> typedefs.JSONObject:
 828        collector = _collect_components(components)
 829        response = await self._request(
 830            _GET,
 831            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
 832            f"Character/{character_id}/?components={collector}",
 833            auth=auth,
 834        )
 835        assert isinstance(response, dict)
 836        return response
 837
 838    async def fetch_activities(
 839        self,
 840        member_id: int,
 841        character_id: int,
 842        mode: enums.GameMode | int,
 843        membership_type: enums.MembershipType | int = enums.MembershipType.ALL,
 844        *,
 845        page: int = 0,
 846        limit: int = 1,
 847    ) -> typedefs.JSONObject:
 848        resp = await self._request(
 849            _GET,
 850            f"Destiny2/{int(membership_type)}/Account/"
 851            f"{member_id}/Character/{character_id}/Stats/Activities"
 852            f"/?mode={int(mode)}&count={limit}&page={page}",
 853        )
 854        assert isinstance(resp, dict)
 855        return resp
 856
 857    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
 858        resp = await self._request(
 859            _GET,
 860            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
 861        )
 862        assert isinstance(resp, dict)
 863        return resp
 864
 865    async def fetch_profile(
 866        self,
 867        membership_id: int,
 868        type: enums.MembershipType | int,
 869        components: collections.Sequence[enums.ComponentType],
 870        auth: str | None = None,
 871    ) -> typedefs.JSONObject:
 872        collector = _collect_components(components)
 873        response = await self._request(
 874            _GET,
 875            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
 876            auth=auth,
 877        )
 878        assert isinstance(response, dict)
 879        return response
 880
 881    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
 882        response = await self._request(_GET, route=f"Destiny2/Manifest/{type}/{hash}")
 883        assert isinstance(response, dict)
 884        return response
 885
 886    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
 887        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
 888        assert isinstance(resp, dict)
 889        return resp
 890
 891    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
 892        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
 893        assert isinstance(resp, dict)
 894        return resp
 895
 896    async def fetch_groups_for_member(
 897        self,
 898        member_id: int,
 899        member_type: enums.MembershipType | int,
 900        /,
 901        *,
 902        filter: int = 0,
 903        group_type: enums.GroupType | int = enums.GroupType.CLAN,
 904    ) -> typedefs.JSONObject:
 905        resp = await self._request(
 906            _GET,
 907            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
 908        )
 909        assert isinstance(resp, dict)
 910        return resp
 911
 912    async def fetch_potential_groups_for_member(
 913        self,
 914        member_id: int,
 915        member_type: enums.MembershipType | int,
 916        /,
 917        *,
 918        filter: int = 0,
 919        group_type: enums.GroupType | int = enums.GroupType.CLAN,
 920    ) -> typedefs.JSONObject:
 921        resp = await self._request(
 922            _GET,
 923            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
 924        )
 925        assert isinstance(resp, dict)
 926        return resp
 927
 928    async def fetch_clan_members(
 929        self,
 930        clan_id: int,
 931        /,
 932        *,
 933        name: str | None = None,
 934        type: enums.MembershipType | int = enums.MembershipType.NONE,
 935    ) -> typedefs.JSONObject:
 936        resp = await self._request(
 937            _GET,
 938            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
 939        )
 940        assert isinstance(resp, dict)
 941        return resp
 942
 943    async def fetch_hardlinked_credentials(
 944        self,
 945        credential: int,
 946        type: enums.CredentialType | int = enums.CredentialType.STEAMID,
 947        /,
 948    ) -> typedefs.JSONObject:
 949        resp = await self._request(
 950            _GET,
 951            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
 952        )
 953        assert isinstance(resp, dict)
 954        return resp
 955
 956    async def fetch_user_credentials(
 957        self, access_token: str, membership_id: int, /
 958    ) -> typedefs.JSONArray:
 959        resp = await self._request(
 960            _GET,
 961            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
 962            auth=access_token,
 963        )
 964        assert isinstance(resp, list)
 965        return resp
 966
 967    async def insert_socket_plug(
 968        self,
 969        action_token: str,
 970        /,
 971        instance_id: int,
 972        plug: builders.PlugSocketBuilder | collections.Mapping[str, int],
 973        character_id: int,
 974        membership_type: enums.MembershipType | int,
 975    ) -> typedefs.JSONObject:
 976        if isinstance(plug, builders.PlugSocketBuilder):
 977            plug = plug.collect()
 978
 979        body = {
 980            "actionToken": action_token,
 981            "itemInstanceId": instance_id,
 982            "plug": plug,
 983            "characterId": character_id,
 984            "membershipType": int(membership_type),
 985        }
 986        resp = await self._request(
 987            _POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
 988        )
 989        assert isinstance(resp, dict)
 990        return resp
 991
 992    async def insert_socket_plug_free(
 993        self,
 994        access_token: str,
 995        /,
 996        instance_id: int,
 997        plug: builders.PlugSocketBuilder | collections.Mapping[str, int],
 998        character_id: int,
 999        membership_type: enums.MembershipType | int,
1000    ) -> typedefs.JSONObject:
1001        if isinstance(plug, builders.PlugSocketBuilder):
1002            plug = plug.collect()
1003
1004        body = {
1005            "itemInstanceId": instance_id,
1006            "plug": plug,
1007            "characterId": character_id,
1008            "membershipType": int(membership_type),
1009        }
1010        resp = await self._request(
1011            _POST,
1012            "Destiny2/Actions/Items/InsertSocketPlugFree",
1013            json=body,
1014            auth=access_token,
1015        )
1016        assert isinstance(resp, dict)
1017        return resp
1018
1019    @helpers.unstable
1020    async def set_item_lock_state(
1021        self,
1022        access_token: str,
1023        state: bool,
1024        /,
1025        item_id: int,
1026        character_id: int,
1027        membership_type: enums.MembershipType | int,
1028    ) -> int:
1029        body = {
1030            "state": state,
1031            "itemId": item_id,
1032            "characterId": character_id,
1033            "membershipType": int(membership_type),
1034        }
1035        response = await self._request(
1036            _POST,
1037            "Destiny2/Actions/Items/SetLockState",
1038            json=body,
1039            auth=access_token,
1040        )
1041        assert isinstance(response, int)
1042        return response
1043
1044    async def set_quest_track_state(
1045        self,
1046        access_token: str,
1047        state: bool,
1048        /,
1049        item_id: int,
1050        character_id: int,
1051        membership_type: enums.MembershipType | int,
1052    ) -> int:
1053        body = {
1054            "state": state,
1055            "itemId": item_id,
1056            "characterId": character_id,
1057            "membership_type": int(membership_type),
1058        }
1059        response = await self._request(
1060            _POST,
1061            "Destiny2/Actions/Items/SetTrackedState",
1062            json=body,
1063            auth=access_token,
1064        )
1065        assert isinstance(response, int)
1066        return response
1067
1068    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1069        path = await self._request(_GET, "Destiny2/Manifest")
1070        assert isinstance(path, dict)
1071        return path
1072
1073    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1074        _ensure_manifest_language(language)
1075
1076        content = await self.fetch_manifest_path()
1077        resp = await self._request(
1078            _GET,
1079            content["mobileWorldContentPaths"][language],
1080            unwrap_bytes=True,
1081            base=True,
1082        )
1083        assert isinstance(resp, bytes)
1084        return resp
1085
1086    async def download_sqlite_manifest(
1087        self,
1088        language: str = "en",
1089        name: str = "manifest",
1090        path: pathlib.Path | str = ".",
1091        *,
1092        force: bool = False,
1093        executor: concurrent.futures.Executor | None = None,
1094    ) -> pathlib.Path:
1095        complete_path = _get_path(name, path, sql=True)
1096
1097        if complete_path.exists() and force:
1098            if force:
1099                _LOGGER.info(
1100                    f"Found manifest in {complete_path!s}. Forcing to Re-Download."
1101                )
1102                complete_path.unlink(missing_ok=True)
1103
1104                return await self.download_sqlite_manifest(
1105                    language, name, path, force=force
1106                )
1107
1108            else:
1109                raise FileExistsError(
1110                    "Manifest file already exists, "
1111                    "To force download, set the `force` parameter to `True`."
1112                )
1113
1114        _LOGGER.info(f"Downloading manifest. Location: {complete_path!s}")
1115        data_bytes = await self.read_manifest_bytes(language)
1116        await asyncio.get_running_loop().run_in_executor(
1117            executor, _write_sqlite_bytes, data_bytes, path, name
1118        )
1119        _LOGGER.info("Finished downloading manifest.")
1120        return _get_path(name, path, sql=True)
1121
1122    async def download_json_manifest(
1123        self,
1124        file_name: str = "manifest",
1125        path: str | pathlib.Path = ".",
1126        *,
1127        language: str = "en",
1128        executor: concurrent.futures.Executor | None = None,
1129    ) -> pathlib.Path:
1130        _ensure_manifest_language(language)
1131        full_path = _get_path(file_name, path)
1132        _LOGGER.info(f"Downloading manifest JSON to {full_path!r}...")
1133
1134        content = await self.fetch_manifest_path()
1135        json_bytes = await self._request(
1136            _GET,
1137            content["jsonWorldContentPaths"][language],
1138            unwrap_bytes=True,
1139            base=True,
1140        )
1141
1142        assert isinstance(json_bytes, bytes)
1143        await asyncio.get_running_loop().run_in_executor(
1144            executor, _write_json_bytes, json_bytes, file_name, path
1145        )
1146        _LOGGER.info("Finished downloading manifest JSON.")
1147        return full_path
1148
1149    async def fetch_manifest_version(self) -> str:
1150        # This is guaranteed str.
1151        return (await self.fetch_manifest_path())["version"]
1152
1153    async def fetch_linked_profiles(
1154        self,
1155        member_id: int,
1156        member_type: enums.MembershipType | int,
1157        /,
1158        *,
1159        all: bool = False,
1160    ) -> typedefs.JSONObject:
1161        resp = await self._request(
1162            _GET,
1163            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1164        )
1165        assert isinstance(resp, dict)
1166        return resp
1167
1168    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1169        resp = await self._request(_GET, "Destiny2/Clan/ClanBannerDictionary/")
1170        assert isinstance(resp, dict)
1171        return resp
1172
1173    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1174        resp = await self._request(_GET, "Destiny2/Milestones/")
1175        assert isinstance(resp, dict)
1176        return resp
1177
1178    async def fetch_public_milestone_content(
1179        self, milestone_hash: int, /
1180    ) -> typedefs.JSONObject:
1181        resp = await self._request(
1182            _GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1183        )
1184        assert isinstance(resp, dict)
1185        return resp
1186
1187    async def fetch_current_user_memberships(
1188        self, access_token: str, /
1189    ) -> typedefs.JSONObject:
1190        resp = await self._request(
1191            _GET,
1192            "User/GetMembershipsForCurrentUser/",
1193            auth=access_token,
1194        )
1195        assert isinstance(resp, dict)
1196        return resp
1197
1198    async def equip_item(
1199        self,
1200        access_token: str,
1201        /,
1202        item_id: int,
1203        character_id: int,
1204        membership_type: enums.MembershipType | int,
1205    ) -> None:
1206        payload = {
1207            "itemId": item_id,
1208            "characterId": character_id,
1209            "membershipType": int(membership_type),
1210        }
1211
1212        await self._request(
1213            _POST,
1214            "Destiny2/Actions/Items/EquipItem/",
1215            json=payload,
1216            auth=access_token,
1217        )
1218
1219    async def equip_items(
1220        self,
1221        access_token: str,
1222        /,
1223        item_ids: collections.Sequence[int],
1224        character_id: int,
1225        membership_type: enums.MembershipType | int,
1226    ) -> None:
1227        payload = {
1228            "itemIds": item_ids,
1229            "characterId": character_id,
1230            "membershipType": int(membership_type),
1231        }
1232        await self._request(
1233            _POST,
1234            "Destiny2/Actions/Items/EquipItems/",
1235            json=payload,
1236            auth=access_token,
1237        )
1238
1239    async def ban_clan_member(
1240        self,
1241        access_token: str,
1242        /,
1243        group_id: int,
1244        membership_id: int,
1245        membership_type: enums.MembershipType | int,
1246        *,
1247        length: int = 0,
1248        comment: str | None = None,
1249    ) -> None:
1250        payload = {"comment": str(comment), "length": length}
1251        await self._request(
1252            _POST,
1253            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1254            json=payload,
1255            auth=access_token,
1256        )
1257
1258    async def unban_clan_member(
1259        self,
1260        access_token: str,
1261        /,
1262        group_id: int,
1263        membership_id: int,
1264        membership_type: enums.MembershipType | int,
1265    ) -> None:
1266        await self._request(
1267            _POST,
1268            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1269            auth=access_token,
1270        )
1271
1272    async def kick_clan_member(
1273        self,
1274        access_token: str,
1275        /,
1276        group_id: int,
1277        membership_id: int,
1278        membership_type: enums.MembershipType | int,
1279    ) -> typedefs.JSONObject:
1280        resp = await self._request(
1281            _POST,
1282            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1283            auth=access_token,
1284        )
1285        assert isinstance(resp, dict)
1286        return resp
1287
1288    async def edit_clan(
1289        self,
1290        access_token: str,
1291        /,
1292        group_id: int,
1293        *,
1294        name: str | None = None,
1295        about: str | None = None,
1296        motto: str | None = None,
1297        theme: str | None = None,
1298        tags: collections.Sequence[str] | None = None,
1299        is_public: bool | None = None,
1300        locale: str | None = None,
1301        avatar_image_index: int | None = None,
1302        membership_option: enums.MembershipOption | int | None = None,
1303        allow_chat: bool | None = None,
1304        chat_security: typing.Literal[0, 1] | None = None,
1305        call_sign: str | None = None,
1306        homepage: typing.Literal[0, 1, 2] | None = None,
1307        enable_invite_messaging_for_admins: bool | None = None,
1308        default_publicity: typing.Literal[0, 1, 2] | None = None,
1309        is_public_topic_admin: bool | None = None,
1310    ) -> None:
1311        payload = {
1312            "name": name,
1313            "about": about,
1314            "motto": motto,
1315            "theme": theme,
1316            "tags": tags,
1317            "isPublic": is_public,
1318            "avatarImageIndex": avatar_image_index,
1319            "isPublicTopicAdminOnly": is_public_topic_admin,
1320            "allowChat": allow_chat,
1321            "chatSecurity": chat_security,
1322            "callsign": call_sign,
1323            "homepage": homepage,
1324            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1325            "defaultPublicity": default_publicity,
1326            "locale": locale,
1327        }
1328        if membership_option is not None:
1329            payload["membershipOption"] = int(membership_option)
1330
1331        await self._request(
1332            _POST,
1333            f"GroupV2/{group_id}/Edit",
1334            json=payload,
1335            auth=access_token,
1336        )
1337
1338    async def edit_clan_options(
1339        self,
1340        access_token: str,
1341        /,
1342        group_id: int,
1343        *,
1344        invite_permissions_override: bool | None = None,
1345        update_culture_permissionOverride: bool | None = None,
1346        host_guided_game_permission_override: typing.Literal[0, 1, 2] | None = None,
1347        update_banner_permission_override: bool | None = None,
1348        join_level: enums.ClanMemberType | int | None = None,
1349    ) -> None:
1350        payload = {
1351            "InvitePermissionOverride": invite_permissions_override,
1352            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1353            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1354            "UpdateBannerPermissionOverride": update_banner_permission_override,
1355            "JoinLevel": int(join_level) if join_level else None,
1356        }
1357
1358        await self._request(
1359            _POST,
1360            f"GroupV2/{group_id}/EditFounderOptions",
1361            json=payload,
1362            auth=access_token,
1363        )
1364
1365    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1366        resp = await self._request(
1367            _GET,
1368            "Social/Friends/",
1369            auth=access_token,
1370        )
1371        assert isinstance(resp, dict)
1372        return resp
1373
1374    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1375        resp = await self._request(
1376            _GET,
1377            "Social/Friends/Requests",
1378            auth=access_token,
1379        )
1380        assert isinstance(resp, dict)
1381        return resp
1382
1383    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1384        await self._request(
1385            _POST,
1386            f"Social/Friends/Requests/Accept/{member_id}",
1387            auth=access_token,
1388        )
1389
1390    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1391        await self._request(
1392            _POST,
1393            f"Social/Friends/Add/{member_id}",
1394            auth=access_token,
1395        )
1396
1397    async def decline_friend_request(
1398        self, access_token: str, /, member_id: int
1399    ) -> None:
1400        await self._request(
1401            _POST,
1402            f"Social/Friends/Requests/Decline/{member_id}",
1403            auth=access_token,
1404        )
1405
1406    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1407        await self._request(
1408            _POST,
1409            f"Social/Friends/Remove/{member_id}",
1410            auth=access_token,
1411        )
1412
1413    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1414        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1415        await self._request(
1416            _POST,
1417            f"Social/Friends/Requests/Remove/{member_id}",
1418            auth=access_token,
1419        )
1420
1421    async def approve_all_pending_group_users(
1422        self,
1423        access_token: str,
1424        /,
1425        group_id: int,
1426        message: str | None = None,
1427    ) -> None:
1428        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1429        await self._request(
1430            _POST,
1431            f"GroupV2/{group_id}/Members/ApproveAll",
1432            auth=access_token,
1433            json={"message": str(message)},
1434        )
1435
1436    async def deny_all_pending_group_users(
1437        self,
1438        access_token: str,
1439        /,
1440        group_id: int,
1441        *,
1442        message: str | None = None,
1443    ) -> None:
1444        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1445        await self._request(
1446            _POST,
1447            f"GroupV2/{group_id}/Members/DenyAll",
1448            auth=access_token,
1449            json={"message": str(message)},
1450        )
1451
1452    async def add_optional_conversation(
1453        self,
1454        access_token: str,
1455        /,
1456        group_id: int,
1457        *,
1458        name: str | None = None,
1459        security: typing.Literal[0, 1] = 0,
1460    ) -> None:
1461        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1462        payload = {"chatName": str(name), "chatSecurity": security}
1463        await self._request(
1464            _POST,
1465            f"GroupV2/{group_id}/OptionalConversations/Add",
1466            json=payload,
1467            auth=access_token,
1468        )
1469
1470    async def edit_optional_conversation(
1471        self,
1472        access_token: str,
1473        /,
1474        group_id: int,
1475        conversation_id: int,
1476        *,
1477        name: str | None = None,
1478        security: typing.Literal[0, 1] = 0,
1479        enable_chat: bool = False,
1480    ) -> None:
1481        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1482        payload = {
1483            "chatEnabled": enable_chat,
1484            "chatName": str(name),
1485            "chatSecurity": security,
1486        }
1487        await self._request(
1488            _POST,
1489            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1490            json=payload,
1491            auth=access_token,
1492        )
1493
1494    async def transfer_item(
1495        self,
1496        access_token: str,
1497        /,
1498        item_id: int,
1499        item_hash: int,
1500        character_id: int,
1501        member_type: enums.MembershipType | int,
1502        *,
1503        stack_size: int = 1,
1504        vault: bool = False,
1505    ) -> None:
1506        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1507        payload = {
1508            "characterId": character_id,
1509            "membershipType": int(member_type),
1510            "itemId": item_id,
1511            "itemReferenceHash": item_hash,
1512            "stackSize": stack_size,
1513            "transferToVault": vault,
1514        }
1515        await self._request(
1516            _POST,
1517            "Destiny2/Actions/Items/TransferItem",
1518            json=payload,
1519            auth=access_token,
1520        )
1521
1522    async def pull_item(
1523        self,
1524        access_token: str,
1525        /,
1526        item_id: int,
1527        item_hash: int,
1528        character_id: int,
1529        member_type: enums.MembershipType | int,
1530        *,
1531        stack_size: int = 1,
1532        vault: bool = False,
1533    ) -> None:
1534        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1535        payload = {
1536            "characterId": character_id,
1537            "membershipType": int(member_type),
1538            "itemId": item_id,
1539            "itemReferenceHash": item_hash,
1540            "stackSize": stack_size,
1541            "transferToVault": vault,
1542        }
1543        await self._request(
1544            _POST,
1545            "Destiny2/Actions/Items/PullFromPostmaster",
1546            json=payload,
1547            auth=access_token,
1548        )
1549
1550    async def fetch_fireteams(
1551        self,
1552        activity_type: fireteams.FireteamActivity | int,
1553        *,
1554        platform: fireteams.FireteamPlatform | int = fireteams.FireteamPlatform.ANY,
1555        language: fireteams.FireteamLanguage | str = fireteams.FireteamLanguage.ALL,
1556        date_range: fireteams.FireteamDate | int = fireteams.FireteamDate.ALL,
1557        page: int = 0,
1558        slots_filter: int = 0,
1559    ) -> typedefs.JSONObject:
1560        resp = await self._request(
1561            _GET,
1562            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1563        )
1564        assert isinstance(resp, dict)
1565        return resp
1566
1567    async def fetch_available_clan_fireteams(
1568        self,
1569        access_token: str,
1570        group_id: int,
1571        activity_type: fireteams.FireteamActivity | int,
1572        *,
1573        platform: fireteams.FireteamPlatform | int,
1574        language: fireteams.FireteamLanguage | str,
1575        date_range: fireteams.FireteamDate | int = fireteams.FireteamDate.ALL,
1576        page: int = 0,
1577        public_only: bool = False,
1578        slots_filter: int = 0,
1579    ) -> typedefs.JSONObject:
1580        resp = await self._request(
1581            _GET,
1582            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1583            json={"langFilter": str(language)},
1584            auth=access_token,
1585        )
1586        assert isinstance(resp, dict)
1587        return resp
1588
1589    async def fetch_clan_fireteam(
1590        self, access_token: str, fireteam_id: int, group_id: int
1591    ) -> typedefs.JSONObject:
1592        resp = await self._request(
1593            _GET,
1594            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1595            auth=access_token,
1596        )
1597        assert isinstance(resp, dict)
1598        return resp
1599
1600    async def fetch_my_clan_fireteams(
1601        self,
1602        access_token: str,
1603        group_id: int,
1604        *,
1605        include_closed: bool = True,
1606        platform: fireteams.FireteamPlatform | int,
1607        language: fireteams.FireteamLanguage | str,
1608        filtered: bool = True,
1609        page: int = 0,
1610    ) -> typedefs.JSONObject:
1611        payload = {"groupFilter": filtered, "langFilter": str(language)}
1612
1613        resp = await self._request(
1614            _GET,
1615            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1616            json=payload,
1617            auth=access_token,
1618        )
1619        assert isinstance(resp, dict)
1620        return resp
1621
1622    async def fetch_private_clan_fireteams(
1623        self, access_token: str, group_id: int, /
1624    ) -> int:
1625        resp = await self._request(
1626            _GET,
1627            f"Fireteam/Clan/{group_id}/ActiveCount",
1628            auth=access_token,
1629        )
1630        assert isinstance(resp, int)
1631        return resp
1632
1633    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1634        resp = await self._request(
1635            _GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1636        )
1637        assert isinstance(resp, dict)
1638        return resp
1639
1640    async def search_entities(
1641        self, name: str, entity_type: str, *, page: int = 0
1642    ) -> typedefs.JSONObject:
1643        resp = await self._request(
1644            _GET,
1645            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1646            json={"page": page},
1647        )
1648        assert isinstance(resp, dict)
1649        return resp
1650
1651    async def fetch_unique_weapon_history(
1652        self,
1653        membership_id: int,
1654        character_id: int,
1655        membership_type: enums.MembershipType | int,
1656    ) -> typedefs.JSONObject:
1657        resp = await self._request(
1658            _GET,
1659            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1660        )
1661        assert isinstance(resp, dict)
1662        return resp
1663
1664    async def fetch_item(
1665        self,
1666        member_id: int,
1667        item_id: int,
1668        membership_type: enums.MembershipType | int,
1669        components: collections.Sequence[enums.ComponentType],
1670    ) -> typedefs.JSONObject:
1671        collector = _collect_components(components)
1672
1673        resp = await self._request(
1674            _GET,
1675            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1676        )
1677        assert isinstance(resp, dict)
1678        return resp
1679
1680    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1681        resp = await self._request(_GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/")
1682        assert isinstance(resp, dict)
1683        return resp
1684
1685    async def fetch_available_locales(self) -> typedefs.JSONObject:
1686        resp = await self._request(_GET, "Destiny2/Manifest/DestinyLocaleDefinition/")
1687        assert isinstance(resp, dict)
1688        return resp
1689
1690    async def fetch_common_settings(self) -> typedefs.JSONObject:
1691        resp = await self._request(_GET, "Settings")
1692        assert isinstance(resp, dict)
1693        return resp
1694
1695    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1696        resp = await self._request(_GET, "UserSystemOverrides")
1697        assert isinstance(resp, dict)
1698        return resp
1699
1700    async def fetch_global_alerts(
1701        self, *, include_streaming: bool = False
1702    ) -> typedefs.JSONArray:
1703        resp = await self._request(
1704            _GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1705        )
1706        assert isinstance(resp, list)
1707        return resp
1708
1709    async def awainitialize_request(
1710        self,
1711        access_token: str,
1712        type: typing.Literal[0, 1],
1713        membership_type: enums.MembershipType | int,
1714        /,
1715        *,
1716        affected_item_id: int | None = None,
1717        character_id: int | None = None,
1718    ) -> typedefs.JSONObject:
1719        body = {"type": type, "membershipType": int(membership_type)}
1720
1721        if affected_item_id is not None:
1722            body["affectedItemId"] = affected_item_id
1723
1724        if character_id is not None:
1725            body["characterId"] = character_id
1726
1727        resp = await self._request(
1728            _POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1729        )
1730        assert isinstance(resp, dict)
1731        return resp
1732
1733    async def awaget_action_token(
1734        self, access_token: str, correlation_id: str, /
1735    ) -> typedefs.JSONObject:
1736        resp = await self._request(
1737            _POST,
1738            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1739            auth=access_token,
1740        )
1741        assert isinstance(resp, dict)
1742        return resp
1743
1744    async def awa_provide_authorization_result(
1745        self,
1746        access_token: str,
1747        selection: int,
1748        correlation_id: str,
1749        nonce: collections.MutableSequence[str | bytes],
1750    ) -> int:
1751        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1752
1753        resp = await self._request(
1754            _POST,
1755            "Destiny2/Awa/AwaProvideAuthorizationResult",
1756            json=body,
1757            auth=access_token,
1758        )
1759        assert isinstance(resp, int)
1760        return resp
1761
1762    async def fetch_vendors(
1763        self,
1764        access_token: str,
1765        character_id: int,
1766        membership_id: int,
1767        membership_type: enums.MembershipType | int,
1768        /,
1769        components: collections.Sequence[enums.ComponentType],
1770        filter: int | None = None,
1771    ) -> typedefs.JSONObject:
1772        components_ = _collect_components(components)
1773        route = (
1774            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1775            f"/Character/{character_id}/Vendors/?components={components_}"
1776        )
1777
1778        if filter is not None:
1779            route = route + f"&filter={filter}"
1780
1781        resp = await self._request(
1782            _GET,
1783            route,
1784            auth=access_token,
1785        )
1786        assert isinstance(resp, dict)
1787        return resp
1788
1789    async def fetch_vendor(
1790        self,
1791        access_token: str,
1792        character_id: int,
1793        membership_id: int,
1794        membership_type: enums.MembershipType | int,
1795        vendor_hash: int,
1796        /,
1797        components: collections.Sequence[enums.ComponentType],
1798    ) -> typedefs.JSONObject:
1799        components_ = _collect_components(components)
1800        resp = await self._request(
1801            _GET,
1802            (
1803                f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1804                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1805            ),
1806            auth=access_token,
1807        )
1808        assert isinstance(resp, dict)
1809        return resp
1810
1811    async def fetch_application_api_usage(
1812        self,
1813        access_token: str,
1814        application_id: int,
1815        /,
1816        *,
1817        start: datetime.datetime | None = None,
1818        end: datetime.datetime | None = None,
1819    ) -> typedefs.JSONObject:
1820        end_date, start_date = time.parse_date_range(end, start)
1821        resp = await self._request(
1822            _GET,
1823            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1824            auth=access_token,
1825        )
1826        assert isinstance(resp, dict)
1827        return resp
1828
1829    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1830        resp = await self._request(_GET, "App/FirstParty")
1831        assert isinstance(resp, list)
1832        return resp
1833
1834    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1835        resp = await self._request(_GET, f"Content/GetContentType/{type}/")
1836        assert isinstance(resp, dict)
1837        return resp
1838
1839    async def fetch_content_by_id(
1840        self, id: int, locale: str, /, *, head: bool = False
1841    ) -> typedefs.JSONObject:
1842        resp = await self._request(
1843            _GET,
1844            f"Content/GetContentById/{id}/{locale}/",
1845            json={"head": head},
1846        )
1847        assert isinstance(resp, dict)
1848        return resp
1849
1850    async def fetch_content_by_tag_and_type(
1851        self, locale: str, tag: str, type: str, *, head: bool = False
1852    ) -> typedefs.JSONObject:
1853        resp = await self._request(
1854            _GET,
1855            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1856            json={"head": head},
1857        )
1858        assert isinstance(resp, dict)
1859        return resp
1860
1861    async def search_content_with_text(
1862        self,
1863        locale: str,
1864        /,
1865        content_type: str,
1866        search_text: str,
1867        tag: str,
1868        *,
1869        page: int | None = None,
1870        source: str | None = None,
1871    ) -> typedefs.JSONObject:
1872        body: typedefs.JSONObject = {
1873            "locale": locale,
1874            "currentpage": page or 1,
1875            "ctype": content_type,
1876            "searchtxt": search_text,
1877            "searchtext": search_text,
1878            "tag": tag,
1879            "source": source,
1880        }
1881
1882        resp = await self._request(_GET, "Content/Search", params=body)
1883        assert isinstance(resp, dict)
1884        return resp
1885
1886    async def search_content_by_tag_and_type(
1887        self,
1888        locale: str,
1889        tag: str,
1890        type: str,
1891        *,
1892        page: int | None = None,
1893    ) -> typedefs.JSONObject:
1894        body: typedefs.JSONObject = {"currentpage": page or 1}
1895
1896        resp = await self._request(
1897            _GET,
1898            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
1899            params=body,
1900        )
1901        assert isinstance(resp, dict)
1902        return resp
1903
1904    async def search_help_articles(
1905        self, text: str, size: str, /
1906    ) -> typedefs.JSONObject:
1907        resp = await self._request(_GET, f"Content/SearchHelpArticles/{text}/{size}/")
1908        assert isinstance(resp, dict)
1909        return resp
1910
1911    async def fetch_topics_page(
1912        self,
1913        category_filter: int,
1914        group: int,
1915        date_filter: int,
1916        sort: str | bytes,
1917        *,
1918        page: int | None = None,
1919        locales: collections.Iterable[str] | None = None,
1920        tag_filter: str | None = None,
1921    ) -> typedefs.JSONObject:
1922        params = {
1923            "locales": ",".join(locales) if locales is not None else "en",
1924        }
1925        if tag_filter:
1926            params["tagstring"] = tag_filter
1927
1928        resp = await self._request(
1929            _GET,
1930            f"Forum/GetTopicsPaged/{page or 0}/0/{group}/{sort!s}/{date_filter}/{category_filter}/",
1931            params=params,
1932        )
1933        assert isinstance(resp, dict)
1934        return resp
1935
1936    async def fetch_core_topics_page(
1937        self,
1938        category_filter: int,
1939        date_filter: int,
1940        sort: str | bytes,
1941        *,
1942        page: int | None = None,
1943        locales: collections.Iterable[str] | None = None,
1944    ) -> typedefs.JSONObject:
1945        resp = await self._request(
1946            _GET,
1947            f"Forum/GetCoreTopicsPaged/{page or 0}"
1948            f"/{sort!s}/{date_filter}/{category_filter}/?locales={','.join(locales) if locales else 'en'}",
1949        )
1950        assert isinstance(resp, dict)
1951        return resp
1952
1953    async def fetch_posts_threaded_page(
1954        self,
1955        parent_post: bool,
1956        page: int,
1957        page_size: int,
1958        parent_post_id: int,
1959        reply_size: int,
1960        root_thread_mode: bool,
1961        sort_mode: int,
1962        show_banned: str | None = None,
1963    ) -> typedefs.JSONObject:
1964        resp = await self._request(
1965            _GET,
1966            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
1967            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
1968            json={"showbanned": show_banned},
1969        )
1970        assert isinstance(resp, dict)
1971        return resp
1972
1973    async def fetch_posts_threaded_page_from_child(
1974        self,
1975        child_id: bool,
1976        page: int,
1977        page_size: int,
1978        reply_size: int,
1979        root_thread_mode: bool,
1980        sort_mode: int,
1981        show_banned: str | None = None,
1982    ) -> typedefs.JSONObject:
1983        resp = await self._request(
1984            _GET,
1985            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
1986            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
1987            json={"showbanned": show_banned},
1988        )
1989        assert isinstance(resp, dict)
1990        return resp
1991
1992    async def fetch_post_and_parent(
1993        self, child_id: int, /, *, show_banned: str | None = None
1994    ) -> typedefs.JSONObject:
1995        resp = await self._request(
1996            _GET,
1997            f"Forum/GetPostAndParent/{child_id}/",
1998            json={"showbanned": show_banned},
1999        )
2000        assert isinstance(resp, dict)
2001        return resp
2002
2003    async def fetch_posts_and_parent_awaiting(
2004        self, child_id: int, /, *, show_banned: str | None = None
2005    ) -> typedefs.JSONObject:
2006        resp = await self._request(
2007            _GET,
2008            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2009            json={"showbanned": show_banned},
2010        )
2011        assert isinstance(resp, dict)
2012        return resp
2013
2014    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2015        resp = await self._request(_GET, f"Forum/GetTopicForContent/{content_id}/")
2016        assert isinstance(resp, int)
2017        return resp
2018
2019    async def fetch_forum_tag_suggestions(
2020        self, partial_tag: str, /
2021    ) -> typedefs.JSONObject:
2022        resp = await self._request(
2023            _GET,
2024            "Forum/GetForumTagSuggestions/",
2025            json={"partialtag": partial_tag},
2026        )
2027        assert isinstance(resp, dict)
2028        return resp
2029
2030    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2031        resp = await self._request(_GET, f"Forum/Poll/{topic_id}/")
2032        assert isinstance(resp, dict)
2033        return resp
2034
2035    async def fetch_recruitment_thread_summaries(self) -> typedefs.JSONArray:
2036        resp = await self._request(_POST, "Forum/Recruit/Summaries/")
2037        assert isinstance(resp, list)
2038        return resp
2039
2040    async def fetch_recommended_groups(
2041        self,
2042        access_token: str,
2043        /,
2044        *,
2045        date_range: int = 0,
2046        group_type: enums.GroupType | int = enums.GroupType.CLAN,
2047    ) -> typedefs.JSONArray:
2048        resp = await self._request(
2049            _POST,
2050            f"GroupV2/Recommended/{int(group_type)}/{date_range}/",
2051            auth=access_token,
2052        )
2053        assert isinstance(resp, list)
2054        return resp
2055
2056    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2057        resp = await self._request(_GET, "GroupV2/GetAvailableAvatars/")
2058        assert isinstance(resp, dict)
2059        return resp
2060
2061    async def fetch_user_clan_invite_setting(
2062        self,
2063        access_token: str,
2064        /,
2065        membership_type: enums.MembershipType | int,
2066    ) -> bool:
2067        resp = await self._request(
2068            _GET,
2069            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2070            auth=access_token,
2071        )
2072        assert isinstance(resp, bool)
2073        return resp
2074
2075    async def fetch_banned_group_members(
2076        self, access_token: str, group_id: int, /, *, page: int = 1
2077    ) -> typedefs.JSONObject:
2078        resp = await self._request(
2079            _GET,
2080            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2081            auth=access_token,
2082        )
2083        assert isinstance(resp, dict)
2084        return resp
2085
2086    async def fetch_pending_group_memberships(
2087        self, access_token: str, group_id: int, /, *, current_page: int = 1
2088    ) -> typedefs.JSONObject:
2089        resp = await self._request(
2090            _GET,
2091            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2092            auth=access_token,
2093        )
2094        assert isinstance(resp, dict)
2095        return resp
2096
2097    async def fetch_invited_group_memberships(
2098        self, access_token: str, group_id: int, /, *, current_page: int = 1
2099    ) -> typedefs.JSONObject:
2100        resp = await self._request(
2101            _GET,
2102            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2103            auth=access_token,
2104        )
2105        assert isinstance(resp, dict)
2106        return resp
2107
2108    async def invite_member_to_group(
2109        self,
2110        access_token: str,
2111        /,
2112        group_id: int,
2113        membership_id: int,
2114        membership_type: enums.MembershipType | int,
2115        *,
2116        message: str | None = None,
2117    ) -> typedefs.JSONObject:
2118        resp = await self._request(
2119            _POST,
2120            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2121            auth=access_token,
2122            json={"message": str(message)},
2123        )
2124        assert isinstance(resp, dict)
2125        return resp
2126
2127    async def cancel_group_member_invite(
2128        self,
2129        access_token: str,
2130        /,
2131        group_id: int,
2132        membership_id: int,
2133        membership_type: enums.MembershipType | int,
2134    ) -> typedefs.JSONObject:
2135        resp = await self._request(
2136            _POST,
2137            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2138            auth=access_token,
2139        )
2140        assert isinstance(resp, dict)
2141        return resp
2142
2143    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2144        resp = await self._request(_GET, "Destiny2/Stats/Definition/")
2145        assert isinstance(resp, dict)
2146        return resp
2147
2148    async def fetch_historical_stats(
2149        self,
2150        character_id: int,
2151        membership_id: int,
2152        membership_type: enums.MembershipType | int,
2153        day_start: datetime.datetime,
2154        day_end: datetime.datetime,
2155        groups: collections.Sequence[enums.StatsGroupType | int],
2156        modes: collections.Sequence[enums.GameMode | int],
2157        *,
2158        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2159    ) -> typedefs.JSONObject:
2160        end, start = time.parse_date_range(day_end, day_start)
2161        resp = await self._request(
2162            _GET,
2163            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2164            json={
2165                "dayend": end,
2166                "daystart": start,
2167                "groups": [str(int(group)) for group in groups],
2168                "modes": [str(int(mode)) for mode in modes],
2169                "periodType": int(period_type),
2170            },
2171        )
2172        assert isinstance(resp, dict)
2173        return resp
2174
2175    async def fetch_historical_stats_for_account(
2176        self,
2177        membership_id: int,
2178        membership_type: enums.MembershipType | int,
2179        groups: collections.Sequence[enums.StatsGroupType | int],
2180    ) -> typedefs.JSONObject:
2181        resp = await self._request(
2182            _GET,
2183            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2184            json={"groups": [str(int(group)) for group in groups]},
2185        )
2186        assert isinstance(resp, dict)
2187        return resp
2188
2189    async def fetch_aggregated_activity_stats(
2190        self,
2191        character_id: int,
2192        membership_id: int,
2193        membership_type: enums.MembershipType | int,
2194        /,
2195    ) -> typedefs.JSONObject:
2196        resp = await self._request(
2197            _GET,
2198            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2199            f"Character/{character_id}/Stats/AggregateActivityStats/",
2200        )
2201        assert isinstance(resp, dict)
2202        return resp
2203
2204    async def equip_loadout(
2205        self,
2206        access_token: str,
2207        /,
2208        loadout_index: int,
2209        character_id: int,
2210        membership_type: enums.MembershipType | int,
2211    ) -> None:
2212        response = await self._request(
2213            _POST,
2214            "Destiny2/Actions/Loadouts/EquipLoadout/",
2215            json={
2216                "loadoutIndex": loadout_index,
2217                "characterId": character_id,
2218                "membership_type": int(membership_type),
2219            },
2220            auth=access_token,
2221        )
2222        assert isinstance(response, int)
2223
2224    async def snapshot_loadout(
2225        self,
2226        access_token: str,
2227        /,
2228        loadout_index: int,
2229        character_id: int,
2230        membership_type: enums.MembershipType | int,
2231        *,
2232        color_hash: int | None = None,
2233        icon_hash: int | None = None,
2234        name_hash: int | None = None,
2235    ) -> None:
2236        response = await self._request(
2237            _POST,
2238            "Destiny2/Actions/Loadouts/SnapshotLoadout/",
2239            auth=access_token,
2240            json={
2241                "colorHash": color_hash,
2242                "iconHash": icon_hash,
2243                "nameHash": name_hash,
2244                "loadoutIndex": loadout_index,
2245                "characterId": character_id,
2246                "membershipType": int(membership_type),
2247            },
2248        )
2249        assert isinstance(response, int)
2250
2251    async def update_loadout(
2252        self,
2253        access_token: str,
2254        /,
2255        loadout_index: int,
2256        character_id: int,
2257        membership_type: enums.MembershipType | int,
2258        *,
2259        color_hash: int | None = None,
2260        icon_hash: int | None = None,
2261        name_hash: int | None = None,
2262    ) -> None:
2263        response = await self._request(
2264            _POST,
2265            "Destiny2/Actions/Loadouts/UpdateLoadoutIdentifiers/",
2266            auth=access_token,
2267            json={
2268                "colorHash": color_hash,
2269                "iconHash": icon_hash,
2270                "nameHash": name_hash,
2271                "loadoutIndex": loadout_index,
2272                "characterId": character_id,
2273                "membershipType": int(membership_type),
2274            },
2275        )
2276        assert isinstance(response, int)
2277
2278    async def clear_loadout(
2279        self,
2280        access_token: str,
2281        /,
2282        loadout_index: int,
2283        character_id: int,
2284        membership_type: enums.MembershipType | int,
2285    ) -> None:
2286        response = await self._request(
2287            _POST,
2288            "Destiny2/Actions/Loadouts/ClearLoadout/",
2289            json={
2290                "loadoutIndex": loadout_index,
2291                "characterId": character_id,
2292                "membership_type": int(membership_type),
2293            },
2294            auth=access_token,
2295        )
2296        assert isinstance(response, int)

A single process REST client implementation.

This client is designed to only make HTTP requests and return raw JSON objects.

Example
import aiobungie

client = aiobungie.RESTClient("TOKEN")
async with client:
    response = await client.fetch_clan_members(4389205)
    for member in response['results']:
        print(member['destinyUserInfo'])
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • client_secret (str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • debug (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | TRACE: This will log the response headers along with the minimal information.
RESTClient( token: str, /, *, client_secret: str | None = None, client_id: int | None = None, client_session: aiohttp.client.ClientSession | None = None, dumps: collections.abc.Callable[[collections.abc.Mapping[str, typing.Any] | collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]], bytes] = <function dumps>, loads: collections.abc.Callable[[str | bytes], collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]] | collections.abc.Mapping[str, typing.Any]] = <function loads>, max_retries: int = 4, debug: Union[Literal['TRACE'], bool, int] = False)
364    def __init__(
365        self,
366        token: str,
367        /,
368        *,
369        client_secret: str | None = None,
370        client_id: int | None = None,
371        client_session: aiohttp.ClientSession | None = None,
372        dumps: typedefs.Dumps = helpers.dumps,
373        loads: typedefs.Loads = helpers.loads,
374        max_retries: int = 4,
375        debug: typing.Literal["TRACE"] | bool | int = False,
376    ) -> None:
377        self._session = client_session
378        self._lock: asyncio.Lock | None = None
379        self._client_secret = client_secret
380        self._client_id = client_id
381        self._token: str = token
382        self._max_retries = max_retries
383        self._dumps = dumps
384        self._loads = loads
385        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
386        self.with_debug(debug)
client_id: int | None
388    @property
389    def client_id(self) -> int | None:
390        return self._client_id

Return the client id of this REST client if provided, Otherwise None.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]
392    @property
393    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
394        return self._metadata

A mutable mapping storage for the user's needs.

This mapping is useful for storing any kind of data that the user may need.

Example
import aiobungie

client = aiobungie.RESTClient(…)

async with client:
    # Fetch auth tokens and store them
    client.metadata["tokens"] = await client.fetch_access_token("code")

# Some other time.
async with client:
    # Retrieve the tokens
    tokens: aiobungie.OAuth2Response = client.metadata["tokens"]

    # Use them to fetch your user.
    user = await client.fetch_current_user_memberships(tokens.access_token)
is_alive: bool
396    @property
397    def is_alive(self) -> bool:
398        return self._session is not None

Returns True if the REST client is alive and False otherwise.

@typing.final
async def close(self) -> None:
400    @typing.final
401    async def close(self) -> None:
402        if self._session is None:
403            raise RuntimeError("REST client is not running.")
404
405        await self._session.close()
406        self._session = None

Close this REST client session if it was acquired.

This method is automatically called when using async with contextmanager.

Raises
  • RuntimeError: If the client is already closed.
@typing.final
def open(self) -> None:
408    @typing.final
409    def open(self) -> None:
410        """Open a new client session. This is called internally with contextmanager usage."""
411        if self._session:
412            raise RuntimeError("Cannot open REST client when it's already open.")
413
414        self._session = aiohttp.ClientSession(
415            connector=aiohttp.TCPConnector(),
416            connector_owner=True,
417            raise_for_status=False,
418            timeout=aiohttp.ClientTimeout(total=30.0),
419        )

Open a new client session. This is called internally with contextmanager usage.

@typing.final
async def static_request( self, method: Literal['GET', 'DELETE', 'POST', 'PUT', 'PATCH'], path: str, *, auth: str | None = None, json: collections.abc.Mapping[str, typing.Any] | None = None) -> collections.abc.Mapping[str, typing.Any] | collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]] | bytes | str | int | bool | None:
421    @typing.final
422    async def static_request(
423        self,
424        method: _HTTP_METHOD,
425        path: str,
426        *,
427        auth: str | None = None,
428        json: collections.Mapping[str, typing.Any] | None = None,
429    ) -> typedefs.JSONIsh:
430        return await self._request(method, path, auth=auth, json=json)

Perform an HTTP request given a valid Bungie endpoint.

Parameters
  • method (str): The request method, This may be GET, POST, PUT, etc.
  • path (str): The Bungie endpoint or path. A path must look something like this Destiny2/3/Profile/46111239123/...
Other Parameters
  • auth (str | None): An optional bearer token for methods that requires OAuth2 Authorization header.
  • json (MutableMapping[str, typing.Any] | None): An optional JSON mapping to include in the request.
Returns
  • aiobungie.typedefs.JSONIsh: The response payload.
@typing.final
def build_oauth2_url(self, client_id: int | None = None) -> aiobungie.builders.OAuthURL | None:
438    @typing.final
439    def build_oauth2_url(
440        self, client_id: int | None = None
441    ) -> builders.OAuthURL | None:
442        client_id = client_id or self._client_id
443        if client_id is None:
444            return None
445
446        return builders.OAuthURL(client_id=client_id)

Builds an OAuth2 URL using the provided user REST/Base client secret/id.

You can't get the complete string URL by using .compile() method.

Parameters
  • client_id (int | None): An optional client id to provide, If left None it will roll back to the id passed to the RESTClient, If both is None this method will return None.
Returns
@typing.final
def with_debug( self, level: Union[Literal['TRACE'], bool, int] = True, file: str | pathlib.Path | None = None) -> None:
448    @typing.final
449    def with_debug(
450        self,
451        level: typing.Literal["TRACE"] | bool | int = True,
452        file: str | pathlib.Path | None = None,
453    ) -> None:
454        """Enable debugging for this client with a level. Defaults to `True`.
455
456        Parameters
457        ----------
458        level: `NotRequired[int | bool | typing.Literal["TRACE"] | None]`
459            The level of the logger. This field is not required.
460        file: `pathlib.Path | str | None`
461            An optional file to write the logs into.
462
463        Logging Levels
464        --------------
465        * `False`: This will disable logging.
466        * `True`: This will set the level to `DEBUG` and enable logging minimal information.
467        * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
468        """
469        logging.logThreads = False
470        logging.logMultiprocessing = False
471        logging.logProcesses = False
472        logging.captureWarnings(True)
473
474        format = "%(levelname)s " "%(asctime)23.23s " "%(name)s: " "%(message)s"
475
476        file_handler = (logging.FileHandler(file),) if file else None
477        if level == "TRACE" or level == TRACE:
478            logging.basicConfig(
479                level=TRACE, format=format, stream=sys.stdout, handlers=file_handler
480            )
481
482        elif level is True:
483            logging.basicConfig(
484                level=logging.DEBUG,
485                format=format,
486                stream=sys.stdout,
487                handlers=file_handler,
488            )

Enable debugging for this client with a level. Defaults to True.

Parameters
  • level (NotRequired[int | bool | typing.Literal["TRACE"] | None]): The level of the logger. This field is not required.
  • file (pathlib.Path | str | None): An optional file to write the logs into.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | TRACE: This will log the response headers along with the minimal information.
async def fetch_oauth2_tokens(self, code: str, /) -> aiobungie.builders.OAuth2Response:
714    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
715        data = {
716            "grant_type": "authorization_code",
717            "code": code,
718            "client_id": self._client_id,
719            "client_secret": self._client_secret,
720        }
721
722        response = await self._request(_POST, "", data=data, oauth2=True)
723        assert isinstance(response, dict)
724        return builders.OAuth2Response.build_response(response)

Makes a POST request and fetch the OAuth2 access_token and refresh token.

Parameters
  • code (str): The Authorization code received from the authorization endpoint found in the URL parameters.
Returns
Raises
async def refresh_access_token(self, refresh_token: str, /) -> aiobungie.builders.OAuth2Response:
726    async def refresh_access_token(
727        self, refresh_token: str, /
728    ) -> builders.OAuth2Response:
729        data = {
730            "grant_type": "refresh_token",
731            "refresh_token": refresh_token,
732            "client_id": self._client_id,
733            "client_secret": self._client_secret,
734        }
735
736        response = await self._request(_POST, "", data=data, oauth2=True)
737        assert isinstance(response, dict)
738        return builders.OAuth2Response.build_response(response)

Refresh OAuth2 access token given its refresh token.

Parameters
  • refresh_token (str): The refresh token.
Returns
async def fetch_bungie_user(self, id: int) -> collections.abc.Mapping[str, typing.Any]:
740    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
741        resp = await self._request(_GET, f"User/GetBungieNetUserById/{id}/")
742        assert isinstance(resp, dict)
743        return resp

Fetch a Bungie user by their id.

Parameters
  • id (int): The user id.
Returns
Raises
async def fetch_user_themes( self) -> collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]:
745    async def fetch_user_themes(self) -> typedefs.JSONArray:
746        resp = await self._request(_GET, "User/GetAvailableThemes/")
747        assert isinstance(resp, list)
748        return resp

Fetch all available user themes.

Returns
async def fetch_membership_from_id( self, id: int, type: MembershipType | int = <MembershipType.NONE: 0>, /) -> collections.abc.Mapping[str, typing.Any]:
750    async def fetch_membership_from_id(
751        self,
752        id: int,
753        type: enums.MembershipType | int = enums.MembershipType.NONE,
754        /,
755    ) -> typedefs.JSONObject:
756        resp = await self._request(_GET, f"User/GetMembershipsById/{id}/{int(type)}")
757        assert isinstance(resp, dict)
758        return resp

Fetch Bungie user's memberships from their id.

Parameters
  • id (int): The user's id.
  • type (aiobungie.aiobungie.MembershipType | int): The user's membership type.
Returns
Raises
async def fetch_membership( self, name: str, code: int, type: MembershipType | int = <MembershipType.ALL: -1>, /) -> collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]:
760    async def fetch_membership(
761        self,
762        name: str,
763        code: int,
764        type: enums.MembershipType | int = enums.MembershipType.ALL,
765        /,
766    ) -> typedefs.JSONArray:
767        resp = await self._request(
768            _POST,
769            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
770            json={"displayName": name, "displayNameCode": code},
771        )
772        assert isinstance(resp, list)
773        return resp

Fetch a Destiny 2 Player.

Parameters
  • name (str): The unique Bungie player name.
  • code (int): The unique Bungie display name code.
  • type (aiobungie.aiobungie.MembershipType | int): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
Raises
async def search_users(self, name: str, /) -> collections.abc.Mapping[str, typing.Any]:
775    async def search_users(self, name: str, /) -> typedefs.JSONObject:
776        resp = await self._request(
777            _POST,
778            "User/Search/GlobalName/0",
779            json={"displayNamePrefix": name},
780        )
781        assert isinstance(resp, dict)
782        return resp

Search for users by their global name and return all users who share this name.

Parameters
  • name (str): The user name.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
784    async def fetch_clan_from_id(
785        self, id: int, /, access_token: str | None = None
786    ) -> typedefs.JSONObject:
787        resp = await self._request(_GET, f"GroupV2/{id}", auth=access_token)
788        assert isinstance(resp, dict)
789        return resp

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Other Parameters
  • access_token (str | None): An optional access token to make the request with.

    If the token was bound to a member of the clan, This field aiobungie.crates.Clan.current_user_membership will be available and will return the membership of the user who made this request.

Returns
Raises
async def fetch_clan( self, name: str, /, access_token: str | None = None, *, type: GroupType | int = <GroupType.CLAN: 1>) -> collections.abc.Mapping[str, typing.Any]:
791    async def fetch_clan(
792        self,
793        name: str,
794        /,
795        access_token: str | None = None,
796        *,
797        type: enums.GroupType | int = enums.GroupType.CLAN,
798    ) -> typedefs.JSONObject:
799        resp = await self._request(
800            _GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
801        )
802        assert isinstance(resp, dict)
803        return resp

Fetch a Clan by its name. This method will return the first clan found with given name name.

Parameters
  • name (str): The clan name.
Other Parameters
  • access_token (str | None): An optional access token to make the request with.

    If the token was bound to a member of the clan, This field aiobungie.crates.Clan.current_user_membership will be available and will return the membership of the user who made this request.

  • type (aiobungie.aiobungie.GroupType | int): The group type, Default is one.
Returns
Raises
async def fetch_clan_admins(self, clan_id: int, /) -> collections.abc.Mapping[str, typing.Any]:
805    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
806        resp = await self._request(_GET, f"GroupV2/{clan_id}/AdminsAndFounder/")
807        assert isinstance(resp, dict)
808        return resp

Fetch the admins and founder members of the clan.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_clan_conversations( self, clan_id: int, /) -> collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]:
810    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
811        resp = await self._request(_GET, f"GroupV2/{clan_id}/OptionalConversations/")
812        assert isinstance(resp, list)
813        return resp

Fetch a clan's conversations.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_application(self, appid: int, /) -> collections.abc.Mapping[str, typing.Any]:
815    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
816        resp = await self._request(_GET, f"App/Application/{appid}")
817        assert isinstance(resp, dict)
818        return resp

Fetch a Bungie Application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_character( self, member_id: int, membership_type: MembershipType | int, character_id: int, components: collections.abc.Sequence[ComponentType], auth: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
820    async def fetch_character(
821        self,
822        member_id: int,
823        membership_type: enums.MembershipType | int,
824        character_id: int,
825        components: collections.Sequence[enums.ComponentType],
826        auth: str | None = None,
827    ) -> typedefs.JSONObject:
828        collector = _collect_components(components)
829        response = await self._request(
830            _GET,
831            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
832            f"Character/{character_id}/?components={collector}",
833            auth=auth,
834        )
835        assert isinstance(response, dict)
836        return response

Fetch a Destiny 2 player's characters.

Parameters
  • member_id (int): A valid bungie member id.
  • membership_type (aiobungie.aiobungie.internal.enums.MembershipType | int): The member's membership type.
  • character_id (int): The character id to return.
  • components (collections.Sequence[aiobungie.ComponentType]): A list of character components to collect and return.
Other Parameters
  • auth (str | None): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_activities( self, member_id: int, character_id: int, mode: GameMode | int, membership_type: MembershipType | int = <MembershipType.ALL: -1>, *, page: int = 0, limit: int = 1) -> collections.abc.Mapping[str, typing.Any]:
838    async def fetch_activities(
839        self,
840        member_id: int,
841        character_id: int,
842        mode: enums.GameMode | int,
843        membership_type: enums.MembershipType | int = enums.MembershipType.ALL,
844        *,
845        page: int = 0,
846        limit: int = 1,
847    ) -> typedefs.JSONObject:
848        resp = await self._request(
849            _GET,
850            f"Destiny2/{int(membership_type)}/Account/"
851            f"{member_id}/Character/{character_id}/Stats/Activities"
852            f"/?mode={int(mode)}&count={limit}&page={page}",
853        )
854        assert isinstance(resp, dict)
855        return resp

Fetch a Destiny 2 activity for the specified user id and character.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve.
  • mode (aiobungie.aiobungie.GameMode | int): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
  • membership_type (aiobungie.aiobungie.internal.enums.MembershipType | int): The Member ship type, if nothing was passed than it will return all.
  • page (int): The page number. Default to 1
  • limit (int): Limit the returned result. Default to 1
Returns
Raises
async def fetch_vendor_sales(self) -> collections.abc.Mapping[str, typing.Any]:
857    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
858        resp = await self._request(
859            _GET,
860            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
861        )
862        assert isinstance(resp, dict)
863        return resp
async def fetch_profile( self, membership_id: int, type: MembershipType | int, components: collections.abc.Sequence[ComponentType], auth: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
865    async def fetch_profile(
866        self,
867        membership_id: int,
868        type: enums.MembershipType | int,
869        components: collections.Sequence[enums.ComponentType],
870        auth: str | None = None,
871    ) -> typedefs.JSONObject:
872        collector = _collect_components(components)
873        response = await self._request(
874            _GET,
875            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
876            auth=auth,
877        )
878        assert isinstance(response, dict)
879        return response

Fetch a bungie profile.

Parameters
  • membership_id (int): The member's id.
  • type (aiobungie.aiobungie.MembershipType | int): A valid membership type.
  • components (collections.Sequence[aiobungie.ComponentType]): A sequence of profile components to collect and return.
Other Parameters
  • auth (str | None): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_entity(self, type: str, hash: int) -> collections.abc.Mapping[str, typing.Any]:
881    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
882        response = await self._request(_GET, route=f"Destiny2/Manifest/{type}/{hash}")
883        assert isinstance(response, dict)
884        return response

Fetch a Destiny definition item given its type and hash.

Parameters
  • type (str): Entity's type definition.
  • hash (int): Entity's hash.
Returns
async def fetch_inventory_item(self, hash: int, /) -> collections.abc.Mapping[str, typing.Any]:
886    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
887        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
888        assert isinstance(resp, dict)
889        return resp

Fetch a Destiny inventory item entity given a its hash.

Parameters
  • hash (int): Entity's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> collections.abc.Mapping[str, typing.Any]:
891    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
892        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
893        assert isinstance(resp, dict)
894        return resp

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def fetch_groups_for_member( self, member_id: int, member_type: MembershipType | int, /, *, filter: int = 0, group_type: GroupType | int = <GroupType.CLAN: 1>) -> collections.abc.Mapping[str, typing.Any]:
896    async def fetch_groups_for_member(
897        self,
898        member_id: int,
899        member_type: enums.MembershipType | int,
900        /,
901        *,
902        filter: int = 0,
903        group_type: enums.GroupType | int = enums.GroupType.CLAN,
904    ) -> typedefs.JSONObject:
905        resp = await self._request(
906            _GET,
907            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
908        )
909        assert isinstance(resp, dict)
910        return resp

Fetch the information about the groups for a member.

Parameters
  • member_id (int): The member's id
  • member_type (aiobungie.aiobungie.MembershipType | int): The member's membership type.
Other Parameters
  • filter (int): Filter apply to list of joined groups. This Default to 0
  • group_type (aiobungie.aiobungie.GroupType | int): The group's type. This is always set to aiobungie.GroupType.CLAN and should not be changed.
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: MembershipType | int, /, *, filter: int = 0, group_type: GroupType | int = <GroupType.CLAN: 1>) -> collections.abc.Mapping[str, typing.Any]:
912    async def fetch_potential_groups_for_member(
913        self,
914        member_id: int,
915        member_type: enums.MembershipType | int,
916        /,
917        *,
918        filter: int = 0,
919        group_type: enums.GroupType | int = enums.GroupType.CLAN,
920    ) -> typedefs.JSONObject:
921        resp = await self._request(
922            _GET,
923            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
924        )
925        assert isinstance(resp, dict)
926        return resp

Get information about the groups that a given member has applied to or been invited to.

Parameters
  • member_id (int): The member's id
  • member_type (aiobungie.aiobungie.MembershipType | int): The member's membership type.
Other Parameters
  • filter (int): Filter apply to list of joined groups. This Default to 0
  • group_type (aiobungie.aiobungie.GroupType | int): The group's type. This is always set to aiobungie.GroupType.CLAN and should not be changed.
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: str | None = None, type: MembershipType | int = <MembershipType.NONE: 0>) -> collections.abc.Mapping[str, typing.Any]:
928    async def fetch_clan_members(
929        self,
930        clan_id: int,
931        /,
932        *,
933        name: str | None = None,
934        type: enums.MembershipType | int = enums.MembershipType.NONE,
935    ) -> typedefs.JSONObject:
936        resp = await self._request(
937            _GET,
938            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
939        )
940        assert isinstance(resp, dict)
941        return resp

Fetch all Bungie Clan members.

Parameters
  • clan_id (int): The clans id
Other Parameters
  • name (str | None): If provided, Only players matching this name will be returned.
  • type (aiobungie.aiobungie.MembershipType | int): An optional clan member's membership type. Default is set to aiobungie.MembershipType.NONE Which returns the first matched clan member by their name.
Returns
Raises
async def fetch_hardlinked_credentials( self, credential: int, type: CredentialType | int = <CredentialType.STEAMID: 12>, /) -> collections.abc.Mapping[str, typing.Any]:
943    async def fetch_hardlinked_credentials(
944        self,
945        credential: int,
946        type: enums.CredentialType | int = enums.CredentialType.STEAMID,
947        /,
948    ) -> typedefs.JSONObject:
949        resp = await self._request(
950            _GET,
951            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
952        )
953        assert isinstance(resp, dict)
954        return resp

Gets any hard linked membership given a credential.

Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
  • credential (int): A valid SteamID64
  • type (aiobungie.aiobungie.CredentialType | int): The credential type. This must not be changed Since its only credential that works "currently"
Returns
async def fetch_user_credentials( self, access_token: str, membership_id: int, /) -> collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]:
956    async def fetch_user_credentials(
957        self, access_token: str, membership_id: int, /
958    ) -> typedefs.JSONArray:
959        resp = await self._request(
960            _GET,
961            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
962            auth=access_token,
963        )
964        assert isinstance(resp, list)
965        return resp

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def insert_socket_plug( self, action_token: str, /, instance_id: int, plug: aiobungie.builders.PlugSocketBuilder | collections.abc.Mapping[str, int], character_id: int, membership_type: MembershipType | int) -> collections.abc.Mapping[str, typing.Any]:
967    async def insert_socket_plug(
968        self,
969        action_token: str,
970        /,
971        instance_id: int,
972        plug: builders.PlugSocketBuilder | collections.Mapping[str, int],
973        character_id: int,
974        membership_type: enums.MembershipType | int,
975    ) -> typedefs.JSONObject:
976        if isinstance(plug, builders.PlugSocketBuilder):
977            plug = plug.collect()
978
979        body = {
980            "actionToken": action_token,
981            "itemInstanceId": instance_id,
982            "plug": plug,
983            "characterId": character_id,
984            "membershipType": int(membership_type),
985        }
986        resp = await self._request(
987            _POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
988        )
989        assert isinstance(resp, dict)
990        return resp

Insert a plug into a socketed item.

OAuth2: AdvancedWriteActions scope is required

Parameters
  • action_token (str): Action token provided by the AwaGetActionToken API call.
  • instance_id (int): The item instance id that's plug inserted.
  • plug (aiobungie.builders.PlugSocketBuilder | Mapping[str, int]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.aiobungie.MembershipType | int The membership type.

Returns
Raises
async def insert_socket_plug_free( self, access_token: str, /, instance_id: int, plug: aiobungie.builders.PlugSocketBuilder | collections.abc.Mapping[str, int], character_id: int, membership_type: MembershipType | int) -> collections.abc.Mapping[str, typing.Any]:
 992    async def insert_socket_plug_free(
 993        self,
 994        access_token: str,
 995        /,
 996        instance_id: int,
 997        plug: builders.PlugSocketBuilder | collections.Mapping[str, int],
 998        character_id: int,
 999        membership_type: enums.MembershipType | int,
1000    ) -> typedefs.JSONObject:
1001        if isinstance(plug, builders.PlugSocketBuilder):
1002            plug = plug.collect()
1003
1004        body = {
1005            "itemInstanceId": instance_id,
1006            "plug": plug,
1007            "characterId": character_id,
1008            "membershipType": int(membership_type),
1009        }
1010        resp = await self._request(
1011            _POST,
1012            "Destiny2/Actions/Items/InsertSocketPlugFree",
1013            json=body,
1014            auth=access_token,
1015        )
1016        assert isinstance(resp, dict)
1017        return resp

Insert a plug into a socketed item. This doesn't require an Action token.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • instance_id (int): The item instance id that's plug inserted.
  • plug (aiobungie.builders.PlugSocketBuilder | Mapping[str, int]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.aiobungie.MembershipType | int The membership type.

Returns
Raises
@helpers.unstable
async def set_item_lock_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: MembershipType | int) -> int:
1019    @helpers.unstable
1020    async def set_item_lock_state(
1021        self,
1022        access_token: str,
1023        state: bool,
1024        /,
1025        item_id: int,
1026        character_id: int,
1027        membership_type: enums.MembershipType | int,
1028    ) -> int:
1029        body = {
1030            "state": state,
1031            "itemId": item_id,
1032            "characterId": character_id,
1033            "membershipType": int(membership_type),
1034        }
1035        response = await self._request(
1036            _POST,
1037            "Destiny2/Actions/Items/SetLockState",
1038            json=body,
1039            auth=access_token,
1040        )
1041        assert isinstance(response, int)
1042        return response

Set the Lock State for an instanced item.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def set_quest_track_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: MembershipType | int) -> int:
1044    async def set_quest_track_state(
1045        self,
1046        access_token: str,
1047        state: bool,
1048        /,
1049        item_id: int,
1050        character_id: int,
1051        membership_type: enums.MembershipType | int,
1052    ) -> int:
1053        body = {
1054            "state": state,
1055            "itemId": item_id,
1056            "characterId": character_id,
1057            "membership_type": int(membership_type),
1058        }
1059        response = await self._request(
1060            _POST,
1061            "Destiny2/Actions/Items/SetTrackedState",
1062            json=body,
1063            auth=access_token,
1064        )
1065        assert isinstance(response, int)
1066        return response

Set the Tracking State for an instanced Quest or Bounty.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def fetch_manifest_path(self) -> collections.abc.Mapping[str, typing.Any]:
1068    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1069        path = await self._request(_GET, "Destiny2/Manifest")
1070        assert isinstance(path, dict)
1071        return path

Fetch the manifest JSON paths.

Returns
  • typedefs.JSONObject: The manifest JSON paths.
async def read_manifest_bytes(self, language: str = 'en', /) -> bytes:
1073    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1074        _ensure_manifest_language(language)
1075
1076        content = await self.fetch_manifest_path()
1077        resp = await self._request(
1078            _GET,
1079            content["mobileWorldContentPaths"][language],
1080            unwrap_bytes=True,
1081            base=True,
1082        )
1083        assert isinstance(resp, bytes)
1084        return resp

Read raw manifest SQLite database bytes response.

This method can be used to write the bytes to zipped file and then extract it to get the manifest content.

Parameters
  • language (str): The manifest database language bytes to get.
Returns
  • bytes: The bytes to read and write the manifest database.
async def download_sqlite_manifest( self, language: str = 'en', name: str = 'manifest', path: pathlib.Path | str = '.', *, force: bool = False, executor: concurrent.futures._base.Executor | None = None) -> pathlib.Path:
1086    async def download_sqlite_manifest(
1087        self,
1088        language: str = "en",
1089        name: str = "manifest",
1090        path: pathlib.Path | str = ".",
1091        *,
1092        force: bool = False,
1093        executor: concurrent.futures.Executor | None = None,
1094    ) -> pathlib.Path:
1095        complete_path = _get_path(name, path, sql=True)
1096
1097        if complete_path.exists() and force:
1098            if force:
1099                _LOGGER.info(
1100                    f"Found manifest in {complete_path!s}. Forcing to Re-Download."
1101                )
1102                complete_path.unlink(missing_ok=True)
1103
1104                return await self.download_sqlite_manifest(
1105                    language, name, path, force=force
1106                )
1107
1108            else:
1109                raise FileExistsError(
1110                    "Manifest file already exists, "
1111                    "To force download, set the `force` parameter to `True`."
1112                )
1113
1114        _LOGGER.info(f"Downloading manifest. Location: {complete_path!s}")
1115        data_bytes = await self.read_manifest_bytes(language)
1116        await asyncio.get_running_loop().run_in_executor(
1117            executor, _write_sqlite_bytes, data_bytes, path, name
1118        )
1119        _LOGGER.info("Finished downloading manifest.")
1120        return _get_path(name, path, sql=True)

Downloads the SQLite version of Destiny2's Manifest.

Example
manifest = await rest.download_sqlite_manifest()
with sqlite3.connect(manifest) as conn:
    ...
Parameters
  • language (str): The manifest language to download, Default is English.
  • path (str | pathlib.Path): The path to download this manifest. Example "/tmp/databases/", Default is the current directory.
  • name (str): The manifest database file name. Default is manifest
  • force (bool): Whether to force the download. Default is False. However if set to true the old file will get unlinked and a new one will begin to download.
  • executor (concurrent.futures.Executor | None): An optional executor which will be used to write the bytes of the manifest.
Returns
  • pathlib.Path: A pathlib object of the .sqlite file.
Raises
  • FileNotFoundError: If the manifest file exists and force is False.
  • ValueError: If the provided language was not recognized.
async def download_json_manifest( self, file_name: str = 'manifest', path: str | pathlib.Path = '.', *, language: str = 'en', executor: concurrent.futures._base.Executor | None = None) -> pathlib.Path:
1122    async def download_json_manifest(
1123        self,
1124        file_name: str = "manifest",
1125        path: str | pathlib.Path = ".",
1126        *,
1127        language: str = "en",
1128        executor: concurrent.futures.Executor | None = None,
1129    ) -> pathlib.Path:
1130        _ensure_manifest_language(language)
1131        full_path = _get_path(file_name, path)
1132        _LOGGER.info(f"Downloading manifest JSON to {full_path!r}...")
1133
1134        content = await self.fetch_manifest_path()
1135        json_bytes = await self._request(
1136            _GET,
1137            content["jsonWorldContentPaths"][language],
1138            unwrap_bytes=True,
1139            base=True,
1140        )
1141
1142        assert isinstance(json_bytes, bytes)
1143        await asyncio.get_running_loop().run_in_executor(
1144            executor, _write_json_bytes, json_bytes, file_name, path
1145        )
1146        _LOGGER.info("Finished downloading manifest JSON.")
1147        return full_path

Download the Bungie manifest json file.

Example
manifest = await rest.download_json_manifest()
with open(manifest, "r") as f:
    to_dict = json.loads(f.read())
    item_definitions = to_dict['DestinyInventoryItemDefinition']
Parameters
  • file_name (str): The file name to save the manifest json file. Default is manifest.
  • path (str | pathlib.Path): The path to save the manifest json file. Default is the current directory. Example "D:/"
  • language (str): The manifest database language bytes to get. Default is English.
  • executor (concurrent.futures.Executor | None): An optional executor which will be used to write the bytes of the manifest.
Returns
  • pathlib.Path: The path of this JSON manifest.
async def fetch_manifest_version(self) -> str:
1149    async def fetch_manifest_version(self) -> str:
1150        # This is guaranteed str.
1151        return (await self.fetch_manifest_path())["version"]

Fetch the manifest version.

Returns
  • str: The manifest version.
async def fetch_linked_profiles( self, member_id: int, member_type: MembershipType | int, /, *, all: bool = False) -> collections.abc.Mapping[str, typing.Any]:
1153    async def fetch_linked_profiles(
1154        self,
1155        member_id: int,
1156        member_type: enums.MembershipType | int,
1157        /,
1158        *,
1159        all: bool = False,
1160    ) -> typedefs.JSONObject:
1161        resp = await self._request(
1162            _GET,
1163            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1164        )
1165        assert isinstance(resp, dict)
1166        return resp

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
  • member_id (int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
  • member_type (aiobungie.aiobungie.MembershipType | int): The type for the membership whose linked Destiny account you want to return.
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether they're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
async def fetch_clan_banners(self) -> collections.abc.Mapping[str, typing.Any]:
1168    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1169        resp = await self._request(_GET, "Destiny2/Clan/ClanBannerDictionary/")
1170        assert isinstance(resp, dict)
1171        return resp

Fetch the values of the clan banners.

Returns
async def fetch_public_milestones(self) -> collections.abc.Mapping[str, typing.Any]:
1173    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1174        resp = await self._request(_GET, "Destiny2/Milestones/")
1175        assert isinstance(resp, dict)
1176        return resp

Fetch the available milestones.

Returns
async def fetch_public_milestone_content(self, milestone_hash: int, /) -> collections.abc.Mapping[str, typing.Any]:
1178    async def fetch_public_milestone_content(
1179        self, milestone_hash: int, /
1180    ) -> typedefs.JSONObject:
1181        resp = await self._request(
1182            _GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1183        )
1184        assert isinstance(resp, dict)
1185        return resp

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
async def fetch_current_user_memberships(self, access_token: str, /) -> collections.abc.Mapping[str, typing.Any]:
1187    async def fetch_current_user_memberships(
1188        self, access_token: str, /
1189    ) -> typedefs.JSONObject:
1190        resp = await self._request(
1191            _GET,
1192            "User/GetMembershipsForCurrentUser/",
1193            auth=access_token,
1194        )
1195        assert isinstance(resp, dict)
1196        return resp

Fetch a bungie user's accounts with the signed in user. This GET method requires a Bearer access token for the authorization.

This requires OAuth2 scope enabled and the valid Bearer access_token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def equip_item( self, access_token: str, /, item_id: int, character_id: int, membership_type: MembershipType | int) -> None:
1198    async def equip_item(
1199        self,
1200        access_token: str,
1201        /,
1202        item_id: int,
1203        character_id: int,
1204        membership_type: enums.MembershipType | int,
1205    ) -> None:
1206        payload = {
1207            "itemId": item_id,
1208            "characterId": character_id,
1209            "membershipType": int(membership_type),
1210        }
1211
1212        await self._request(
1213            _POST,
1214            "Destiny2/Actions/Items/EquipItem/",
1215            json=payload,
1216            auth=access_token,
1217        )

Equip an item to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item id.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The membership type associated with this player.
async def equip_items( self, access_token: str, /, item_ids: collections.abc.Sequence[int], character_id: int, membership_type: MembershipType | int) -> None:
1219    async def equip_items(
1220        self,
1221        access_token: str,
1222        /,
1223        item_ids: collections.Sequence[int],
1224        character_id: int,
1225        membership_type: enums.MembershipType | int,
1226    ) -> None:
1227        payload = {
1228            "itemIds": item_ids,
1229            "characterId": character_id,
1230            "membershipType": int(membership_type),
1231        }
1232        await self._request(
1233            _POST,
1234            "Destiny2/Actions/Items/EquipItems/",
1235            json=payload,
1236            auth=access_token,
1237        )

Equip multiple items to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_ids (Sequence[int]): A sequence of item ids.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The membership type associated with this player.
async def ban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: MembershipType | int, *, length: int = 0, comment: str | None = None) -> None:
1239    async def ban_clan_member(
1240        self,
1241        access_token: str,
1242        /,
1243        group_id: int,
1244        membership_id: int,
1245        membership_type: enums.MembershipType | int,
1246        *,
1247        length: int = 0,
1248        comment: str | None = None,
1249    ) -> None:
1250        payload = {"comment": str(comment), "length": length}
1251        await self._request(
1252            _POST,
1253            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1254            json=payload,
1255            auth=access_token,
1256        )

Bans a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to ban.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The member's membership type.
Other Parameters
  • length (int): An optional ban length.
  • comment (aiobungie.UndefinedOr[str]): An optional comment to this ban. Default is UNDEFINED
async def unban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: MembershipType | int) -> None:
1258    async def unban_clan_member(
1259        self,
1260        access_token: str,
1261        /,
1262        group_id: int,
1263        membership_id: int,
1264        membership_type: enums.MembershipType | int,
1265    ) -> None:
1266        await self._request(
1267            _POST,
1268            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1269            auth=access_token,
1270        )

Unban a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to unban.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The member's membership type.
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: MembershipType | int) -> collections.abc.Mapping[str, typing.Any]:
1272    async def kick_clan_member(
1273        self,
1274        access_token: str,
1275        /,
1276        group_id: int,
1277        membership_id: int,
1278        membership_type: enums.MembershipType | int,
1279    ) -> typedefs.JSONObject:
1280        resp = await self._request(
1281            _POST,
1282            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1283            auth=access_token,
1284        )
1285        assert isinstance(resp, dict)
1286        return resp

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The member's membership type.
Returns
async def edit_clan( self, access_token: str, /, group_id: int, *, name: str | None = None, about: str | None = None, motto: str | None = None, theme: str | None = None, tags: collections.abc.Sequence[str] | None = None, is_public: bool | None = None, locale: str | None = None, avatar_image_index: int | None = None, membership_option: MembershipOption | int | None = None, allow_chat: bool | None = None, chat_security: Optional[Literal[0, 1]] = None, call_sign: str | None = None, homepage: Optional[Literal[0, 1, 2]] = None, enable_invite_messaging_for_admins: bool | None = None, default_publicity: Optional[Literal[0, 1, 2]] = None, is_public_topic_admin: bool | None = None) -> None:
1288    async def edit_clan(
1289        self,
1290        access_token: str,
1291        /,
1292        group_id: int,
1293        *,
1294        name: str | None = None,
1295        about: str | None = None,
1296        motto: str | None = None,
1297        theme: str | None = None,
1298        tags: collections.Sequence[str] | None = None,
1299        is_public: bool | None = None,
1300        locale: str | None = None,
1301        avatar_image_index: int | None = None,
1302        membership_option: enums.MembershipOption | int | None = None,
1303        allow_chat: bool | None = None,
1304        chat_security: typing.Literal[0, 1] | None = None,
1305        call_sign: str | None = None,
1306        homepage: typing.Literal[0, 1, 2] | None = None,
1307        enable_invite_messaging_for_admins: bool | None = None,
1308        default_publicity: typing.Literal[0, 1, 2] | None = None,
1309        is_public_topic_admin: bool | None = None,
1310    ) -> None:
1311        payload = {
1312            "name": name,
1313            "about": about,
1314            "motto": motto,
1315            "theme": theme,
1316            "tags": tags,
1317            "isPublic": is_public,
1318            "avatarImageIndex": avatar_image_index,
1319            "isPublicTopicAdminOnly": is_public_topic_admin,
1320            "allowChat": allow_chat,
1321            "chatSecurity": chat_security,
1322            "callsign": call_sign,
1323            "homepage": homepage,
1324            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1325            "defaultPublicity": default_publicity,
1326            "locale": locale,
1327        }
1328        if membership_option is not None:
1329            payload["membershipOption"] = int(membership_option)
1330
1331        await self._request(
1332            _POST,
1333            f"GroupV2/{group_id}/Edit",
1334            json=payload,
1335            auth=access_token,
1336        )

Edit a clan.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id to edit.
Other Parameters
  • name (str | None): The name to edit the clan with.
  • about (str | None): The about section to edit the clan with.
  • motto (str | None): The motto section to edit the clan with.
  • theme (str | None): The theme name to edit the clan with.
  • tags (collections.Sequence[str] | None): A sequence of strings to replace the clan tags with.
  • is_public (bool | None): If provided and set to True, The clan will set to private. If provided and set to False, The clan will set to public whether it was or not.
  • locale (str | None): The locale section to edit the clan with.
  • avatar_image_index (int | None): The clan avatar image index to edit the clan with.
  • membership_option : aiobungie.typedefs.NoneOr[aiobungie.aiobungie.MembershipOption | int] # noqa (E501 # Line too long): The clan membership option to edit it with.
  • allow_chat (bool | None): If provided and set to True, The clan members will be allowed to chat. If provided and set to False, The clan members will not be allowed to chat.
  • chat_security (aiobungie.typedefs.NoneOr[typing.Literal[0, 1]]): If provided and set to 0, The clan chat security will be edited to Group only. If provided and set to 1, The clan chat security will be edited to Admin only.
  • call_sign (str | None): The clan call sign to edit it with.
  • homepage (aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to 0, The clan chat homepage will be edited to Wall. If provided and set to 1, The clan chat homepage will be edited to Forum. If provided and set to 0, The clan chat homepage will be edited to AllianceForum.
  • enable_invite_messaging_for_admins (bool | None): ???
  • default_publicity (aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to 0, The clan chat publicity will be edited to Public. If provided and set to 1, The clan chat publicity will be edited to Alliance. If provided and set to 2, The clan chat publicity will be edited to Private.
  • is_public_topic_admin (bool | None): ???
async def edit_clan_options( self, access_token: str, /, group_id: int, *, invite_permissions_override: bool | None = None, update_culture_permissionOverride: bool | None = None, host_guided_game_permission_override: Optional[Literal[0, 1, 2]] = None, update_banner_permission_override: bool | None = None, join_level: ClanMemberType | int | None = None) -> None:
1338    async def edit_clan_options(
1339        self,
1340        access_token: str,
1341        /,
1342        group_id: int,
1343        *,
1344        invite_permissions_override: bool | None = None,
1345        update_culture_permissionOverride: bool | None = None,
1346        host_guided_game_permission_override: typing.Literal[0, 1, 2] | None = None,
1347        update_banner_permission_override: bool | None = None,
1348        join_level: enums.ClanMemberType | int | None = None,
1349    ) -> None:
1350        payload = {
1351            "InvitePermissionOverride": invite_permissions_override,
1352            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1353            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1354            "UpdateBannerPermissionOverride": update_banner_permission_override,
1355            "JoinLevel": int(join_level) if join_level else None,
1356        }
1357
1358        await self._request(
1359            _POST,
1360            f"GroupV2/{group_id}/EditFounderOptions",
1361            json=payload,
1362            auth=access_token,
1363        )

Edit the clan options.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
Other Parameters
  • invite_permissions_override (bool | None): Minimum Member Level allowed to invite new members to group Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • update_culture_permissionOverride (bool | None): Minimum Member Level allowed to update group culture Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • host_guided_game_permission_override (aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): Minimum Member Level allowed to host guided games Always Allowed: Founder, Acting Founder, Admin Allowed Overrides: 0 -> None, 1 -> Beginner 2 -> Member. Default is Member for clans, None for groups, although this means nothing for groups.
  • update_banner_permission_override (bool | None): Minimum Member Level allowed to update banner Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • join_level (aiobungie.ClanMemberType): Level to join a member at when accepting an invite, application, or joining an open clan. Default is aiobungie.ClanMemberType.BEGINNER
async def fetch_friends(self, access_token: str, /) -> collections.abc.Mapping[str, typing.Any]:
1365    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1366        resp = await self._request(
1367            _GET,
1368            "Social/Friends/",
1369            auth=access_token,
1370        )
1371        assert isinstance(resp, dict)
1372        return resp

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> collections.abc.Mapping[str, typing.Any]:
1374    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1375        resp = await self._request(
1376            _GET,
1377            "Social/Friends/Requests",
1378            auth=access_token,
1379        )
1380        assert isinstance(resp, dict)
1381        return resp

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1383    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1384        await self._request(
1385            _POST,
1386            f"Social/Friends/Requests/Accept/{member_id}",
1387            auth=access_token,
1388        )

Accepts a friend relationship with the target user. The user must be on your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to accept.
async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1390    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1391        await self._request(
1392            _POST,
1393            f"Social/Friends/Add/{member_id}",
1394            auth=access_token,
1395        )

Requests a friend relationship with the target user.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to send the request to.
async def decline_friend_request(self, access_token: str, /, member_id: int) -> None:
1397    async def decline_friend_request(
1398        self, access_token: str, /, member_id: int
1399    ) -> None:
1400        await self._request(
1401            _POST,
1402            f"Social/Friends/Requests/Decline/{member_id}",
1403            auth=access_token,
1404        )

Decline a friend request with the target user. The user must be in your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to decline.
async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1406    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1407        await self._request(
1408            _POST,
1409            f"Social/Friends/Remove/{member_id}",
1410            auth=access_token,
1411        )

Removes a friend from your friend list. The user must be in your friend list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove.
async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1413    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1414        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1415        await self._request(
1416            _POST,
1417            f"Social/Friends/Requests/Remove/{member_id}",
1418            auth=access_token,
1419        )

Removes a friend from your friend list requests. The user must be in your outgoing request list.

.. note : This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove from the requested friend list.
async def approve_all_pending_group_users( self, access_token: str, /, group_id: int, message: str | None = None) -> None:
1421    async def approve_all_pending_group_users(
1422        self,
1423        access_token: str,
1424        /,
1425        group_id: int,
1426        message: str | None = None,
1427    ) -> None:
1428        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1429        await self._request(
1430            _POST,
1431            f"GroupV2/{group_id}/Members/ApproveAll",
1432            auth=access_token,
1433            json={"message": str(message)},
1434        )

Approve all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
  • message (aiobungie.UndefinedOr[str]): An optional message to send with the request. Default is UNDEFINED.
async def deny_all_pending_group_users( self, access_token: str, /, group_id: int, *, message: str | None = None) -> None:
1436    async def deny_all_pending_group_users(
1437        self,
1438        access_token: str,
1439        /,
1440        group_id: int,
1441        *,
1442        message: str | None = None,
1443    ) -> None:
1444        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1445        await self._request(
1446            _POST,
1447            f"GroupV2/{group_id}/Members/DenyAll",
1448            auth=access_token,
1449            json={"message": str(message)},
1450        )

Deny all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
  • message (aiobungie.UndefinedOr[str]): An optional message to send with the request. Default is UNDEFINED.
async def add_optional_conversation( self, access_token: str, /, group_id: int, *, name: str | None = None, security: Literal[0, 1] = 0) -> None:
1452    async def add_optional_conversation(
1453        self,
1454        access_token: str,
1455        /,
1456        group_id: int,
1457        *,
1458        name: str | None = None,
1459        security: typing.Literal[0, 1] = 0,
1460    ) -> None:
1461        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1462        payload = {"chatName": str(name), "chatSecurity": security}
1463        await self._request(
1464            _POST,
1465            f"GroupV2/{group_id}/OptionalConversations/Add",
1466            json=payload,
1467            auth=access_token,
1468        )

Add a new chat channel to a group.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other parameters

name: aiobungie.UndefinedOr[str] The chat name. Default to UNDEFINED security: typing.Literal[0, 1] The security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
async def edit_optional_conversation( self, access_token: str, /, group_id: int, conversation_id: int, *, name: str | None = None, security: Literal[0, 1] = 0, enable_chat: bool = False) -> None:
1470    async def edit_optional_conversation(
1471        self,
1472        access_token: str,
1473        /,
1474        group_id: int,
1475        conversation_id: int,
1476        *,
1477        name: str | None = None,
1478        security: typing.Literal[0, 1] = 0,
1479        enable_chat: bool = False,
1480    ) -> None:
1481        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1482        payload = {
1483            "chatEnabled": enable_chat,
1484            "chatName": str(name),
1485            "chatSecurity": security,
1486        }
1487        await self._request(
1488            _POST,
1489            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1490            json=payload,
1491            auth=access_token,
1492        )

Edit the settings of this chat channel.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
  • conversation_id (int): The conversation/chat id.
Other parameters

name: aiobungie.UndefinedOr[str] The new chat name. Default to UNDEFINED security: typing.Literal[0, 1] The new security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`

enable_chat : bool Whether to enable chatting or not. If set to True then chatting will be enabled. Otherwise it will be disabled.

async def transfer_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: MembershipType | int, *, stack_size: int = 1, vault: bool = False) -> None:
1494    async def transfer_item(
1495        self,
1496        access_token: str,
1497        /,
1498        item_id: int,
1499        item_hash: int,
1500        character_id: int,
1501        member_type: enums.MembershipType | int,
1502        *,
1503        stack_size: int = 1,
1504        vault: bool = False,
1505    ) -> None:
1506        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1507        payload = {
1508            "characterId": character_id,
1509            "membershipType": int(member_type),
1510            "itemId": item_id,
1511            "itemReferenceHash": item_hash,
1512            "stackSize": stack_size,
1513            "transferToVault": vault,
1514        }
1515        await self._request(
1516            _POST,
1517            "Destiny2/Actions/Items/TransferItem",
1518            json=payload,
1519            auth=access_token,
1520        )

Transfer an item from / to your vault.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id you to transfer.
  • item_hash (int): The item hash.
  • character_id (int): The character id to transfer the item from/to.
  • member_type (aiobungie.aiobungie.MembershipType | int): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • vault (bool): Whether to transfer this item to your vault or not. Defaults to False.
async def pull_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: MembershipType | int, *, stack_size: int = 1, vault: bool = False) -> None:
1522    async def pull_item(
1523        self,
1524        access_token: str,
1525        /,
1526        item_id: int,
1527        item_hash: int,
1528        character_id: int,
1529        member_type: enums.MembershipType | int,
1530        *,
1531        stack_size: int = 1,
1532        vault: bool = False,
1533    ) -> None:
1534        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1535        payload = {
1536            "characterId": character_id,
1537            "membershipType": int(member_type),
1538            "itemId": item_id,
1539            "itemReferenceHash": item_hash,
1540            "stackSize": stack_size,
1541            "transferToVault": vault,
1542        }
1543        await self._request(
1544            _POST,
1545            "Destiny2/Actions/Items/PullFromPostmaster",
1546            json=payload,
1547            auth=access_token,
1548        )

pull an item from the postmaster.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id to pull.
  • item_hash (int): The item hash.
  • character_id (int): The character id to pull the item to.
  • member_type (aiobungie.aiobungie.MembershipType | int): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • vault (bool): Whether to pill this item to your vault or not. Defaults to False.
async def fetch_fireteams( self, activity_type: FireteamActivity | int, *, platform: FireteamPlatform | int = <FireteamPlatform.ANY: 0>, language: FireteamLanguage | str = <FireteamLanguage.ALL: >, date_range: FireteamDate | int = <FireteamDate.ALL: 0>, page: int = 0, slots_filter: int = 0) -> collections.abc.Mapping[str, typing.Any]:
1550    async def fetch_fireteams(
1551        self,
1552        activity_type: fireteams.FireteamActivity | int,
1553        *,
1554        platform: fireteams.FireteamPlatform | int = fireteams.FireteamPlatform.ANY,
1555        language: fireteams.FireteamLanguage | str = fireteams.FireteamLanguage.ALL,
1556        date_range: fireteams.FireteamDate | int = fireteams.FireteamDate.ALL,
1557        page: int = 0,
1558        slots_filter: int = 0,
1559    ) -> typedefs.JSONObject:
1560        resp = await self._request(
1561            _GET,
1562            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1563        )
1564        assert isinstance(resp, dict)
1565        return resp

Fetch public Bungie fireteams with open slots.

Parameters
  • activity_type (aiobungie.aiobungie.crates.FireteamActivity | int): The fireteam activity type.
Other Parameters
  • platform (aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (aiobungie.aiobungie.FireteamDate | int): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_available_clan_fireteams( self, access_token: str, group_id: int, activity_type: FireteamActivity | int, *, platform: FireteamPlatform | int, language: FireteamLanguage | str, date_range: FireteamDate | int = <FireteamDate.ALL: 0>, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> collections.abc.Mapping[str, typing.Any]:
1567    async def fetch_available_clan_fireteams(
1568        self,
1569        access_token: str,
1570        group_id: int,
1571        activity_type: fireteams.FireteamActivity | int,
1572        *,
1573        platform: fireteams.FireteamPlatform | int,
1574        language: fireteams.FireteamLanguage | str,
1575        date_range: fireteams.FireteamDate | int = fireteams.FireteamDate.ALL,
1576        page: int = 0,
1577        public_only: bool = False,
1578        slots_filter: int = 0,
1579    ) -> typedefs.JSONObject:
1580        resp = await self._request(
1581            _GET,
1582            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1583            json={"langFilter": str(language)},
1584            auth=access_token,
1585        )
1586        assert isinstance(resp, dict)
1587        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.aiobungie.crates.FireteamActivity | int): The fireteam activity type.
Other Parameters
  • platform (aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (aiobungie.aiobungie.FireteamDate | int): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> collections.abc.Mapping[str, typing.Any]:
1589    async def fetch_clan_fireteam(
1590        self, access_token: str, fireteam_id: int, group_id: int
1591    ) -> typedefs.JSONObject:
1592        resp = await self._request(
1593            _GET,
1594            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1595            auth=access_token,
1596        )
1597        assert isinstance(resp, dict)
1598        return resp

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: FireteamPlatform | int, language: FireteamLanguage | str, filtered: bool = True, page: int = 0) -> collections.abc.Mapping[str, typing.Any]:
1600    async def fetch_my_clan_fireteams(
1601        self,
1602        access_token: str,
1603        group_id: int,
1604        *,
1605        include_closed: bool = True,
1606        platform: fireteams.FireteamPlatform | int,
1607        language: fireteams.FireteamLanguage | str,
1608        filtered: bool = True,
1609        page: int = 0,
1610    ) -> typedefs.JSONObject:
1611        payload = {"groupFilter": filtered, "langFilter": str(language)}
1612
1613        resp = await self._request(
1614            _GET,
1615            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1616            json=payload,
1617            auth=access_token,
1618        )
1619        assert isinstance(resp, dict)
1620        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_private_clan_fireteams(self, access_token: str, group_id: int, /) -> int:
1622    async def fetch_private_clan_fireteams(
1623        self, access_token: str, group_id: int, /
1624    ) -> int:
1625        resp = await self._request(
1626            _GET,
1627            f"Fireteam/Clan/{group_id}/ActiveCount",
1628            auth=access_token,
1629        )
1630        assert isinstance(resp, int)
1631        return resp

Fetch the active count of the clan fireteams that are only private.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id.
Returns
  • int: The active fireteams count. Max value returned is 25.
async def fetch_post_activity(self, instance_id: int, /) -> collections.abc.Mapping[str, typing.Any]:
1633    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1634        resp = await self._request(
1635            _GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1636        )
1637        assert isinstance(resp, dict)
1638        return resp

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> collections.abc.Mapping[str, typing.Any]:
1640    async def search_entities(
1641        self, name: str, entity_type: str, *, page: int = 0
1642    ) -> typedefs.JSONObject:
1643        resp = await self._request(
1644            _GET,
1645            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1646            json={"page": page},
1647        )
1648        assert isinstance(resp, dict)
1649        return resp

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: MembershipType | int) -> collections.abc.Mapping[str, typing.Any]:
1651    async def fetch_unique_weapon_history(
1652        self,
1653        membership_id: int,
1654        character_id: int,
1655        membership_type: enums.MembershipType | int,
1656    ) -> typedefs.JSONObject:
1657        resp = await self._request(
1658            _GET,
1659            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1660        )
1661        assert isinstance(resp, dict)
1662        return resp

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
  • membership_id (int): The Destiny user membership id.
  • character_id (int): The character id to retrieve.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The Destiny user's membership type.
Returns
async def fetch_item( self, member_id: int, item_id: int, membership_type: MembershipType | int, components: collections.abc.Sequence[ComponentType]) -> collections.abc.Mapping[str, typing.Any]:
1664    async def fetch_item(
1665        self,
1666        member_id: int,
1667        item_id: int,
1668        membership_type: enums.MembershipType | int,
1669        components: collections.Sequence[enums.ComponentType],
1670    ) -> typedefs.JSONObject:
1671        collector = _collect_components(components)
1672
1673        resp = await self._request(
1674            _GET,
1675            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1676        )
1677        assert isinstance(resp, dict)
1678        return resp

Fetch an instanced Destiny 2 item's details.

Parameters
  • member_id (int): The membership id of the Destiny 2 player.
  • item_id (int): The instance id of the item.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The membership type of the Destiny 2 player.
  • components (collections.Sequence[aiobungie.ComponentType]): A list of components to retrieve.
Returns
async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> collections.abc.Mapping[str, typing.Any]:
1680    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1681        resp = await self._request(_GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/")
1682        assert isinstance(resp, dict)
1683        return resp

Fetch the weekly reward state for a clan.

Parameters
  • clan_id (int): The clan id.
Returns
async def fetch_available_locales(self) -> collections.abc.Mapping[str, typing.Any]:
1685    async def fetch_available_locales(self) -> typedefs.JSONObject:
1686        resp = await self._request(_GET, "Destiny2/Manifest/DestinyLocaleDefinition/")
1687        assert isinstance(resp, dict)
1688        return resp

Fetch available locales at Bungie.

Returns
async def fetch_common_settings(self) -> collections.abc.Mapping[str, typing.Any]:
1690    async def fetch_common_settings(self) -> typedefs.JSONObject:
1691        resp = await self._request(_GET, "Settings")
1692        assert isinstance(resp, dict)
1693        return resp

Fetch the common settings used by Bungie's environment.

Returns
async def fetch_user_systems_overrides(self) -> collections.abc.Mapping[str, typing.Any]:
1695    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1696        resp = await self._request(_GET, "UserSystemOverrides")
1697        assert isinstance(resp, dict)
1698        return resp

Fetch a user's specific system overrides.

Returns
async def fetch_global_alerts( self, *, include_streaming: bool = False) -> collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]:
1700    async def fetch_global_alerts(
1701        self, *, include_streaming: bool = False
1702    ) -> typedefs.JSONArray:
1703        resp = await self._request(
1704            _GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1705        )
1706        assert isinstance(resp, list)
1707        return resp

Fetch any active global alerts.

Parameters
  • include_streaming (bool): If True, the returned results will include streaming alerts. Default is False.
Returns
async def awainitialize_request( self, access_token: str, type: Literal[0, 1], membership_type: MembershipType | int, /, *, affected_item_id: int | None = None, character_id: int | None = None) -> collections.abc.Mapping[str, typing.Any]:
1709    async def awainitialize_request(
1710        self,
1711        access_token: str,
1712        type: typing.Literal[0, 1],
1713        membership_type: enums.MembershipType | int,
1714        /,
1715        *,
1716        affected_item_id: int | None = None,
1717        character_id: int | None = None,
1718    ) -> typedefs.JSONObject:
1719        body = {"type": type, "membershipType": int(membership_type)}
1720
1721        if affected_item_id is not None:
1722            body["affectedItemId"] = affected_item_id
1723
1724        if character_id is not None:
1725            body["characterId"] = character_id
1726
1727        resp = await self._request(
1728            _POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1729        )
1730        assert isinstance(resp, dict)
1731        return resp

Initialize a request to perform an advanced write action.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • type (typing.Literal[0, 1]): Type of the advanced write action. Its either 0 or 1. If set to 0 that means it None. Otherwise if 1 that means its insert plugs.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The Destiny membership type of the account to modify.
Other Parameters
  • affected_item_id (int | None): Item instance ID the action shall be applied to. This is optional for all but a new AwaType values.
  • character_id (int | None): The Destiny character ID to perform this action on.
Returns
async def awaget_action_token( self, access_token: str, correlation_id: str, /) -> collections.abc.Mapping[str, typing.Any]:
1733    async def awaget_action_token(
1734        self, access_token: str, correlation_id: str, /
1735    ) -> typedefs.JSONObject:
1736        resp = await self._request(
1737            _POST,
1738            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1739            auth=access_token,
1740        )
1741        assert isinstance(resp, dict)
1742        return resp

Returns the action token if user approves the request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • correlation_id (str): The identifier for the advanced write action request.
Returns
async def awa_provide_authorization_result( self, access_token: str, selection: int, correlation_id: str, nonce: collections.abc.MutableSequence[str | bytes]) -> int:
1744    async def awa_provide_authorization_result(
1745        self,
1746        access_token: str,
1747        selection: int,
1748        correlation_id: str,
1749        nonce: collections.MutableSequence[str | bytes],
1750    ) -> int:
1751        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1752
1753        resp = await self._request(
1754            _POST,
1755            "Destiny2/Awa/AwaProvideAuthorizationResult",
1756            json=body,
1757            auth=access_token,
1758        )
1759        assert isinstance(resp, int)
1760        return resp

Provide the result of the user interaction. Called by the Bungie Destiny App to approve or reject a request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • selection (int): Indication of the selection the user has made (Approving or rejecting the action)
  • correlation_id (str): Correlation ID of the request.
  • nonce (collections.MutableSequence[str | bytes]): Secret nonce received via the PUSH notification.
Returns
  • int: ...
async def fetch_vendors( self, access_token: str, character_id: int, membership_id: int, membership_type: MembershipType | int, /, components: collections.abc.Sequence[ComponentType], filter: int | None = None) -> collections.abc.Mapping[str, typing.Any]:
1762    async def fetch_vendors(
1763        self,
1764        access_token: str,
1765        character_id: int,
1766        membership_id: int,
1767        membership_type: enums.MembershipType | int,
1768        /,
1769        components: collections.Sequence[enums.ComponentType],
1770        filter: int | None = None,
1771    ) -> typedefs.JSONObject:
1772        components_ = _collect_components(components)
1773        route = (
1774            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1775            f"/Character/{character_id}/Vendors/?components={components_}"
1776        )
1777
1778        if filter is not None:
1779            route = route + f"&filter={filter}"
1780
1781        resp = await self._request(
1782            _GET,
1783            route,
1784            auth=access_token,
1785        )
1786        assert isinstance(resp, dict)
1787        return resp

Get currently available vendors from the list of vendors that can possibly have rotating inventory.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The Destiny membership type to return the vendor info for.
  • components (collections.Sequence[aiobungie.ComponentType]): A list of vendor components to collect and return.
Other Parameters
  • filter (int): Filters the type of items returned from the vendor. This can be left to None.
Returns
async def fetch_vendor( self, access_token: str, character_id: int, membership_id: int, membership_type: MembershipType | int, vendor_hash: int, /, components: collections.abc.Sequence[ComponentType]) -> collections.abc.Mapping[str, typing.Any]:
1789    async def fetch_vendor(
1790        self,
1791        access_token: str,
1792        character_id: int,
1793        membership_id: int,
1794        membership_type: enums.MembershipType | int,
1795        vendor_hash: int,
1796        /,
1797        components: collections.Sequence[enums.ComponentType],
1798    ) -> typedefs.JSONObject:
1799        components_ = _collect_components(components)
1800        resp = await self._request(
1801            _GET,
1802            (
1803                f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1804                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1805            ),
1806            auth=access_token,
1807        )
1808        assert isinstance(resp, dict)
1809        return resp

Fetch details for a specific vendor.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The Destiny membership type to return the vendor info for.
  • vendor_hash (int): The vendor hash to return the details for.
  • components (collections.Sequence[aiobungie.ComponentType]): A list of vendor components to collect and return.
Returns
async def fetch_application_api_usage( self, access_token: str, application_id: int, /, *, start: datetime.datetime | None = None, end: datetime.datetime | None = None) -> collections.abc.Mapping[str, typing.Any]:
1811    async def fetch_application_api_usage(
1812        self,
1813        access_token: str,
1814        application_id: int,
1815        /,
1816        *,
1817        start: datetime.datetime | None = None,
1818        end: datetime.datetime | None = None,
1819    ) -> typedefs.JSONObject:
1820        end_date, start_date = time.parse_date_range(end, start)
1821        resp = await self._request(
1822            _GET,
1823            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1824            auth=access_token,
1825        )
1826        assert isinstance(resp, dict)
1827        return resp

Fetch a Bungie application's API usage.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • application_id (int): The application id to get.
Other Parameters
  • start (datetime.datetime | None): A datetime object can be used to collect the start of the application usage. This is limited and can go back to 30 days maximum.

    If this is left to None. It will return the last 24 hours.

  • end (datetime.datetime | None): A datetime object can be used to collect the end of the application usage.

    If this is left to None. It will return now.

Example
import datetime

# Fetch data from 2021 Dec 10th to 2021 Dec 20th
await fetch_application_api_usage(
    start=datetime.datetime(2021, 12, 10),
    end=datetime.datetime(2021, 12, 20)
)
Returns
async def fetch_bungie_applications( self) -> collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]:
1829    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1830        resp = await self._request(_GET, "App/FirstParty")
1831        assert isinstance(resp, list)
1832        return resp

Fetch details for applications created by Bungie.

Returns
async def fetch_content_type(self, type: str, /) -> collections.abc.Mapping[str, typing.Any]:
1834    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1835        resp = await self._request(_GET, f"Content/GetContentType/{type}/")
1836        assert isinstance(resp, dict)
1837        return resp
async def fetch_content_by_id( self, id: int, locale: str, /, *, head: bool = False) -> collections.abc.Mapping[str, typing.Any]:
1839    async def fetch_content_by_id(
1840        self, id: int, locale: str, /, *, head: bool = False
1841    ) -> typedefs.JSONObject:
1842        resp = await self._request(
1843            _GET,
1844            f"Content/GetContentById/{id}/{locale}/",
1845            json={"head": head},
1846        )
1847        assert isinstance(resp, dict)
1848        return resp
async def fetch_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, head: bool = False) -> collections.abc.Mapping[str, typing.Any]:
1850    async def fetch_content_by_tag_and_type(
1851        self, locale: str, tag: str, type: str, *, head: bool = False
1852    ) -> typedefs.JSONObject:
1853        resp = await self._request(
1854            _GET,
1855            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1856            json={"head": head},
1857        )
1858        assert isinstance(resp, dict)
1859        return resp
async def search_content_with_text( self, locale: str, /, content_type: str, search_text: str, tag: str, *, page: int | None = None, source: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
1861    async def search_content_with_text(
1862        self,
1863        locale: str,
1864        /,
1865        content_type: str,
1866        search_text: str,
1867        tag: str,
1868        *,
1869        page: int | None = None,
1870        source: str | None = None,
1871    ) -> typedefs.JSONObject:
1872        body: typedefs.JSONObject = {
1873            "locale": locale,
1874            "currentpage": page or 1,
1875            "ctype": content_type,
1876            "searchtxt": search_text,
1877            "searchtext": search_text,
1878            "tag": tag,
1879            "source": source,
1880        }
1881
1882        resp = await self._request(_GET, "Content/Search", params=body)
1883        assert isinstance(resp, dict)
1884        return resp
async def search_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, page: int | None = None) -> collections.abc.Mapping[str, typing.Any]:
1886    async def search_content_by_tag_and_type(
1887        self,
1888        locale: str,
1889        tag: str,
1890        type: str,
1891        *,
1892        page: int | None = None,
1893    ) -> typedefs.JSONObject:
1894        body: typedefs.JSONObject = {"currentpage": page or 1}
1895
1896        resp = await self._request(
1897            _GET,
1898            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
1899            params=body,
1900        )
1901        assert isinstance(resp, dict)
1902        return resp
async def search_help_articles( self, text: str, size: str, /) -> collections.abc.Mapping[str, typing.Any]:
1904    async def search_help_articles(
1905        self, text: str, size: str, /
1906    ) -> typedefs.JSONObject:
1907        resp = await self._request(_GET, f"Content/SearchHelpArticles/{text}/{size}/")
1908        assert isinstance(resp, dict)
1909        return resp
async def fetch_topics_page( self, category_filter: int, group: int, date_filter: int, sort: str | bytes, *, page: int | None = None, locales: collections.abc.Iterable[str] | None = None, tag_filter: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
1911    async def fetch_topics_page(
1912        self,
1913        category_filter: int,
1914        group: int,
1915        date_filter: int,
1916        sort: str | bytes,
1917        *,
1918        page: int | None = None,
1919        locales: collections.Iterable[str] | None = None,
1920        tag_filter: str | None = None,
1921    ) -> typedefs.JSONObject:
1922        params = {
1923            "locales": ",".join(locales) if locales is not None else "en",
1924        }
1925        if tag_filter:
1926            params["tagstring"] = tag_filter
1927
1928        resp = await self._request(
1929            _GET,
1930            f"Forum/GetTopicsPaged/{page or 0}/0/{group}/{sort!s}/{date_filter}/{category_filter}/",
1931            params=params,
1932        )
1933        assert isinstance(resp, dict)
1934        return resp
async def fetch_core_topics_page( self, category_filter: int, date_filter: int, sort: str | bytes, *, page: int | None = None, locales: collections.abc.Iterable[str] | None = None) -> collections.abc.Mapping[str, typing.Any]:
1936    async def fetch_core_topics_page(
1937        self,
1938        category_filter: int,
1939        date_filter: int,
1940        sort: str | bytes,
1941        *,
1942        page: int | None = None,
1943        locales: collections.Iterable[str] | None = None,
1944    ) -> typedefs.JSONObject:
1945        resp = await self._request(
1946            _GET,
1947            f"Forum/GetCoreTopicsPaged/{page or 0}"
1948            f"/{sort!s}/{date_filter}/{category_filter}/?locales={','.join(locales) if locales else 'en'}",
1949        )
1950        assert isinstance(resp, dict)
1951        return resp
async def fetch_posts_threaded_page( self, parent_post: bool, page: int, page_size: int, parent_post_id: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
1953    async def fetch_posts_threaded_page(
1954        self,
1955        parent_post: bool,
1956        page: int,
1957        page_size: int,
1958        parent_post_id: int,
1959        reply_size: int,
1960        root_thread_mode: bool,
1961        sort_mode: int,
1962        show_banned: str | None = None,
1963    ) -> typedefs.JSONObject:
1964        resp = await self._request(
1965            _GET,
1966            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
1967            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
1968            json={"showbanned": show_banned},
1969        )
1970        assert isinstance(resp, dict)
1971        return resp
async def fetch_posts_threaded_page_from_child( self, child_id: bool, page: int, page_size: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
1973    async def fetch_posts_threaded_page_from_child(
1974        self,
1975        child_id: bool,
1976        page: int,
1977        page_size: int,
1978        reply_size: int,
1979        root_thread_mode: bool,
1980        sort_mode: int,
1981        show_banned: str | None = None,
1982    ) -> typedefs.JSONObject:
1983        resp = await self._request(
1984            _GET,
1985            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
1986            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
1987            json={"showbanned": show_banned},
1988        )
1989        assert isinstance(resp, dict)
1990        return resp
async def fetch_post_and_parent( self, child_id: int, /, *, show_banned: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
1992    async def fetch_post_and_parent(
1993        self, child_id: int, /, *, show_banned: str | None = None
1994    ) -> typedefs.JSONObject:
1995        resp = await self._request(
1996            _GET,
1997            f"Forum/GetPostAndParent/{child_id}/",
1998            json={"showbanned": show_banned},
1999        )
2000        assert isinstance(resp, dict)
2001        return resp
async def fetch_posts_and_parent_awaiting( self, child_id: int, /, *, show_banned: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
2003    async def fetch_posts_and_parent_awaiting(
2004        self, child_id: int, /, *, show_banned: str | None = None
2005    ) -> typedefs.JSONObject:
2006        resp = await self._request(
2007            _GET,
2008            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2009            json={"showbanned": show_banned},
2010        )
2011        assert isinstance(resp, dict)
2012        return resp
async def fetch_topic_for_content(self, content_id: int, /) -> int:
2014    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2015        resp = await self._request(_GET, f"Forum/GetTopicForContent/{content_id}/")
2016        assert isinstance(resp, int)
2017        return resp
async def fetch_forum_tag_suggestions(self, partial_tag: str, /) -> collections.abc.Mapping[str, typing.Any]:
2019    async def fetch_forum_tag_suggestions(
2020        self, partial_tag: str, /
2021    ) -> typedefs.JSONObject:
2022        resp = await self._request(
2023            _GET,
2024            "Forum/GetForumTagSuggestions/",
2025            json={"partialtag": partial_tag},
2026        )
2027        assert isinstance(resp, dict)
2028        return resp
async def fetch_poll(self, topic_id: int, /) -> collections.abc.Mapping[str, typing.Any]:
2030    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2031        resp = await self._request(_GET, f"Forum/Poll/{topic_id}/")
2032        assert isinstance(resp, dict)
2033        return resp
async def fetch_recruitment_thread_summaries( self) -> collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]:
2035    async def fetch_recruitment_thread_summaries(self) -> typedefs.JSONArray:
2036        resp = await self._request(_POST, "Forum/Recruit/Summaries/")
2037        assert isinstance(resp, list)
2038        return resp
async def fetch_available_avatars(self) -> collections.abc.Mapping[str, int]:
2056    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2057        resp = await self._request(_GET, "GroupV2/GetAvailableAvatars/")
2058        assert isinstance(resp, dict)
2059        return resp
async def fetch_user_clan_invite_setting( self, access_token: str, /, membership_type: MembershipType | int) -> bool:
2061    async def fetch_user_clan_invite_setting(
2062        self,
2063        access_token: str,
2064        /,
2065        membership_type: enums.MembershipType | int,
2066    ) -> bool:
2067        resp = await self._request(
2068            _GET,
2069            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2070            auth=access_token,
2071        )
2072        assert isinstance(resp, bool)
2073        return resp
async def fetch_banned_group_members( self, access_token: str, group_id: int, /, *, page: int = 1) -> collections.abc.Mapping[str, typing.Any]:
2075    async def fetch_banned_group_members(
2076        self, access_token: str, group_id: int, /, *, page: int = 1
2077    ) -> typedefs.JSONObject:
2078        resp = await self._request(
2079            _GET,
2080            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2081            auth=access_token,
2082        )
2083        assert isinstance(resp, dict)
2084        return resp
async def fetch_pending_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> collections.abc.Mapping[str, typing.Any]:
2086    async def fetch_pending_group_memberships(
2087        self, access_token: str, group_id: int, /, *, current_page: int = 1
2088    ) -> typedefs.JSONObject:
2089        resp = await self._request(
2090            _GET,
2091            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2092            auth=access_token,
2093        )
2094        assert isinstance(resp, dict)
2095        return resp
async def fetch_invited_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> collections.abc.Mapping[str, typing.Any]:
2097    async def fetch_invited_group_memberships(
2098        self, access_token: str, group_id: int, /, *, current_page: int = 1
2099    ) -> typedefs.JSONObject:
2100        resp = await self._request(
2101            _GET,
2102            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2103            auth=access_token,
2104        )
2105        assert isinstance(resp, dict)
2106        return resp
async def invite_member_to_group( self, access_token: str, /, group_id: int, membership_id: int, membership_type: MembershipType | int, *, message: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
2108    async def invite_member_to_group(
2109        self,
2110        access_token: str,
2111        /,
2112        group_id: int,
2113        membership_id: int,
2114        membership_type: enums.MembershipType | int,
2115        *,
2116        message: str | None = None,
2117    ) -> typedefs.JSONObject:
2118        resp = await self._request(
2119            _POST,
2120            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2121            auth=access_token,
2122            json={"message": str(message)},
2123        )
2124        assert isinstance(resp, dict)
2125        return resp
async def cancel_group_member_invite( self, access_token: str, /, group_id: int, membership_id: int, membership_type: MembershipType | int) -> collections.abc.Mapping[str, typing.Any]:
2127    async def cancel_group_member_invite(
2128        self,
2129        access_token: str,
2130        /,
2131        group_id: int,
2132        membership_id: int,
2133        membership_type: enums.MembershipType | int,
2134    ) -> typedefs.JSONObject:
2135        resp = await self._request(
2136            _POST,
2137            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2138            auth=access_token,
2139        )
2140        assert isinstance(resp, dict)
2141        return resp
async def fetch_historical_definition(self) -> collections.abc.Mapping[str, typing.Any]:
2143    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2144        resp = await self._request(_GET, "Destiny2/Stats/Definition/")
2145        assert isinstance(resp, dict)
2146        return resp
async def fetch_historical_stats( self, character_id: int, membership_id: int, membership_type: MembershipType | int, day_start: datetime.datetime, day_end: datetime.datetime, groups: collections.abc.Sequence[aiobungie.internal.enums.StatsGroupType | int], modes: collections.abc.Sequence[GameMode | int], *, period_type: aiobungie.internal.enums.PeriodType = <PeriodType.ALL_TIME: 2>) -> collections.abc.Mapping[str, typing.Any]:
2148    async def fetch_historical_stats(
2149        self,
2150        character_id: int,
2151        membership_id: int,
2152        membership_type: enums.MembershipType | int,
2153        day_start: datetime.datetime,
2154        day_end: datetime.datetime,
2155        groups: collections.Sequence[enums.StatsGroupType | int],
2156        modes: collections.Sequence[enums.GameMode | int],
2157        *,
2158        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2159    ) -> typedefs.JSONObject:
2160        end, start = time.parse_date_range(day_end, day_start)
2161        resp = await self._request(
2162            _GET,
2163            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2164            json={
2165                "dayend": end,
2166                "daystart": start,
2167                "groups": [str(int(group)) for group in groups],
2168                "modes": [str(int(mode)) for mode in modes],
2169                "periodType": int(period_type),
2170            },
2171        )
2172        assert isinstance(resp, dict)
2173        return resp

Fetch historical stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • day_start (datetime.datetime): The start of the day to return the stats for.
  • day_end (datetime.datetime): The end of the day to return the stats for.
  • groups (collections.Sequence[aiobungie.StatsGroupType]): A list of stats groups to return.
  • modes (collections.Sequence[aiobungie.GameMode | int]): A list of game modes to return.
  • period_type (aiobungie.enums.PeriodType): The period type to return the stats for. This will return ALL_TIME by default if not modified.
Returns
async def fetch_historical_stats_for_account( self, membership_id: int, membership_type: MembershipType | int, groups: collections.abc.Sequence[aiobungie.internal.enums.StatsGroupType | int]) -> collections.abc.Mapping[str, typing.Any]:
2175    async def fetch_historical_stats_for_account(
2176        self,
2177        membership_id: int,
2178        membership_type: enums.MembershipType | int,
2179        groups: collections.Sequence[enums.StatsGroupType | int],
2180    ) -> typedefs.JSONObject:
2181        resp = await self._request(
2182            _GET,
2183            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2184            json={"groups": [str(int(group)) for group in groups]},
2185        )
2186        assert isinstance(resp, dict)
2187        return resp

Fetch historical stats for an account's membership.

Parameters
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • groups (collections.Sequence[aiobungie.StatsGroupType]): A list of stats groups to return.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: MembershipType | int, /) -> collections.abc.Mapping[str, typing.Any]:
2189    async def fetch_aggregated_activity_stats(
2190        self,
2191        character_id: int,
2192        membership_id: int,
2193        membership_type: enums.MembershipType | int,
2194        /,
2195    ) -> typedefs.JSONObject:
2196        resp = await self._request(
2197            _GET,
2198            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2199            f"Character/{character_id}/Stats/AggregateActivityStats/",
2200        )
2201        assert isinstance(resp, dict)
2202        return resp

Fetch aggregated activity stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
Returns
async def equip_loadout( self, access_token: str, /, loadout_index: int, character_id: int, membership_type: MembershipType | int) -> None:
2204    async def equip_loadout(
2205        self,
2206        access_token: str,
2207        /,
2208        loadout_index: int,
2209        character_id: int,
2210        membership_type: enums.MembershipType | int,
2211    ) -> None:
2212        response = await self._request(
2213            _POST,
2214            "Destiny2/Actions/Loadouts/EquipLoadout/",
2215            json={
2216                "loadoutIndex": loadout_index,
2217                "characterId": character_id,
2218                "membership_type": int(membership_type),
2219            },
2220            auth=access_token,
2221        )
2222        assert isinstance(response, int)

Equip a loadout. Your character must be in a Social space, Orbit or Offline while performing this operation.

This operation requires MoveEquipDestinyItems OAuth2 scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • loadout_index (int): The index of the loadout to use.
  • character_id (int): The character ID to equip the loadout to.
  • membership_type (aiobungie.MembershipType | int): The membership type of the account.
async def snapshot_loadout( self, access_token: str, /, loadout_index: int, character_id: int, membership_type: MembershipType | int, *, color_hash: int | None = None, icon_hash: int | None = None, name_hash: int | None = None) -> None:
2224    async def snapshot_loadout(
2225        self,
2226        access_token: str,
2227        /,
2228        loadout_index: int,
2229        character_id: int,
2230        membership_type: enums.MembershipType | int,
2231        *,
2232        color_hash: int | None = None,
2233        icon_hash: int | None = None,
2234        name_hash: int | None = None,
2235    ) -> None:
2236        response = await self._request(
2237            _POST,
2238            "Destiny2/Actions/Loadouts/SnapshotLoadout/",
2239            auth=access_token,
2240            json={
2241                "colorHash": color_hash,
2242                "iconHash": icon_hash,
2243                "nameHash": name_hash,
2244                "loadoutIndex": loadout_index,
2245                "characterId": character_id,
2246                "membershipType": int(membership_type),
2247            },
2248        )
2249        assert isinstance(response, int)

Snapshot a loadout with the currently equipped items.

This operation requires MoveEquipDestinyItems OAuth2 scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • loadout_index (int): The index of the loadout to use.
  • character_id (int): The character ID to equip the loadout to.
  • membership_type (aiobungie.MembershipType | int): The membership type of the account.
Other Parameters
  • color_hash (int | None): ...
  • icon_hash (int | None): ...
  • name_hash (int | None): ...
async def update_loadout( self, access_token: str, /, loadout_index: int, character_id: int, membership_type: MembershipType | int, *, color_hash: int | None = None, icon_hash: int | None = None, name_hash: int | None = None) -> None:
2251    async def update_loadout(
2252        self,
2253        access_token: str,
2254        /,
2255        loadout_index: int,
2256        character_id: int,
2257        membership_type: enums.MembershipType | int,
2258        *,
2259        color_hash: int | None = None,
2260        icon_hash: int | None = None,
2261        name_hash: int | None = None,
2262    ) -> None:
2263        response = await self._request(
2264            _POST,
2265            "Destiny2/Actions/Loadouts/UpdateLoadoutIdentifiers/",
2266            auth=access_token,
2267            json={
2268                "colorHash": color_hash,
2269                "iconHash": icon_hash,
2270                "nameHash": name_hash,
2271                "loadoutIndex": loadout_index,
2272                "characterId": character_id,
2273                "membershipType": int(membership_type),
2274            },
2275        )
2276        assert isinstance(response, int)

Update the loadout. Color, Icon and Name.

This operation requires MoveEquipDestinyItems OAuth2 scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • loadout_index (int): The index of the loadout to use.
  • character_id (int): The character ID to equip the loadout to.
  • membership_type (aiobungie.MembershipType | int): The membership type of the account.
Other Parameters
  • color_hash (int | None): The new color hash of the loadout to update.
  • icon_hash (int | None): The new icon hash of the loadout to update.
  • name_hash (int | None): The new name hash of the loadout to update.
async def clear_loadout( self, access_token: str, /, loadout_index: int, character_id: int, membership_type: MembershipType | int) -> None:
2278    async def clear_loadout(
2279        self,
2280        access_token: str,
2281        /,
2282        loadout_index: int,
2283        character_id: int,
2284        membership_type: enums.MembershipType | int,
2285    ) -> None:
2286        response = await self._request(
2287            _POST,
2288            "Destiny2/Actions/Loadouts/ClearLoadout/",
2289            json={
2290                "loadoutIndex": loadout_index,
2291                "characterId": character_id,
2292                "membership_type": int(membership_type),
2293            },
2294            auth=access_token,
2295        )
2296        assert isinstance(response, int)

Clear the identifiers and items of a loadout.

This operation requires MoveEquipDestinyItems OAuth2 scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • loadout_index (int): The index of the loadout to use.
  • character_id (int): The character ID to equip the loadout to.
  • membership_type (aiobungie.MembershipType | int): The membership type of the account.
class RESTPool:
192class RESTPool:
193    """a Pool of `RESTClient` instances.
194
195    This allows to acquire multiple instances of `RESTClient`s which can be acquired with the same token and metadata.
196
197    A full example of this client can be found in the examples directory.
198
199    Example
200    -------
201    ```py
202    import aiobungie
203    import asyncio
204
205    pool = aiobungie.RESTPool("token")
206    pool.metadata['auth_code'] = 'code'
207
208    async def get() -> None:
209        async with pool.acquire() as rest:
210            this = await rest.fetch_current_user_memberships(pool.metadata['auth_code'])
211
212    await asyncio.run(get())
213    ```
214
215    Parameters
216    ----------
217    token : `str`
218        A valid application token from Bungie's developer portal.
219
220    Other Parameters
221    ----------------
222    max_retries : `int`
223        The max retries number to retry if the request hit a `5xx` status code.
224    client_secret : `str | None`
225        An optional application client secret,
226        This is only needed if you're fetching OAuth2 tokens with this client.
227    client_id : `int | None`
228        An optional application client id,
229        This is only needed if you're fetching OAuth2 tokens with this client.
230    debug : `bool | str`
231        Whether to enable logging responses or not.
232
233    Logging Levels
234    --------------
235    * `False`: This will disable logging.
236    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
237    Like the response status, route, taken time and so on.
238    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
239    """
240
241    __slots__ = (
242        "_token",
243        "_max_retries",
244        "_client_secret",
245        "_client_id",
246        "_metadata",
247        "_enable_debug",
248        "_client_session",
249        "_loads",
250        "_dumps",
251    )
252
253    # Looks like mypy doesn't like this.
254    if typing.TYPE_CHECKING:
255        _enable_debug: typing.Literal["TRACE"] | bool | int
256
257    def __init__(
258        self,
259        token: str,
260        /,
261        *,
262        client_secret: str | None = None,
263        client_id: int | None = None,
264        client_session: aiohttp.ClientSession | None = None,
265        dumps: typedefs.Dumps = helpers.dumps,
266        loads: typedefs.Loads = helpers.loads,
267        max_retries: int = 4,
268        debug: typing.Literal["TRACE"] | bool | int = False,
269    ) -> None:
270        self._client_secret = client_secret
271        self._client_id = client_id
272        self._token = token
273        self._max_retries = max_retries
274        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
275        self._enable_debug = debug
276        self._client_session = client_session
277        self._loads = loads
278        self._dumps = dumps
279
280    @property
281    def client_id(self) -> int | None:
282        return self._client_id
283
284    @property
285    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
286        """Pool's Metadata. This is different from client instance metadata."""
287        return self._metadata
288
289    @typing.final
290    def acquire(self) -> RESTClient:
291        """Acquires a new `RESTClient` instance from this pool.
292
293        Returns
294        -------
295        `RESTClient`
296            An instance of a `RESTClient`.
297        """
298        return RESTClient(
299            self._token,
300            client_secret=self._client_secret,
301            client_id=self._client_id,
302            loads=self._loads,
303            dumps=self._dumps,
304            max_retries=self._max_retries,
305            debug=self._enable_debug,
306            client_session=self._client_session,
307        )

a Pool of RESTClient instances.

This allows to acquire multiple instances of RESTClients which can be acquired with the same token and metadata.

A full example of this client can be found in the examples directory.

Example
import aiobungie
import asyncio

pool = aiobungie.RESTPool("token")
pool.metadata['auth_code'] = 'code'

async def get() -> None:
    async with pool.acquire() as rest:
        this = await rest.fetch_current_user_memberships(pool.metadata['auth_code'])

await asyncio.run(get())
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • client_secret (str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • debug (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information. Like the response status, route, taken time and so on.
  • "TRACE" | TRACE: This will log the response headers along with the minimal information.
RESTPool( token: str, /, *, client_secret: str | None = None, client_id: int | None = None, client_session: aiohttp.client.ClientSession | None = None, dumps: collections.abc.Callable[[collections.abc.Mapping[str, typing.Any] | collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]], bytes] = <function dumps>, loads: collections.abc.Callable[[str | bytes], collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]] | collections.abc.Mapping[str, typing.Any]] = <function loads>, max_retries: int = 4, debug: Union[Literal['TRACE'], bool, int] = False)
257    def __init__(
258        self,
259        token: str,
260        /,
261        *,
262        client_secret: str | None = None,
263        client_id: int | None = None,
264        client_session: aiohttp.ClientSession | None = None,
265        dumps: typedefs.Dumps = helpers.dumps,
266        loads: typedefs.Loads = helpers.loads,
267        max_retries: int = 4,
268        debug: typing.Literal["TRACE"] | bool | int = False,
269    ) -> None:
270        self._client_secret = client_secret
271        self._client_id = client_id
272        self._token = token
273        self._max_retries = max_retries
274        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
275        self._enable_debug = debug
276        self._client_session = client_session
277        self._loads = loads
278        self._dumps = dumps
client_id: int | None
280    @property
281    def client_id(self) -> int | None:
282        return self._client_id
metadata: collections.abc.MutableMapping[typing.Any, typing.Any]
284    @property
285    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
286        """Pool's Metadata. This is different from client instance metadata."""
287        return self._metadata

Pool's Metadata. This is different from client instance metadata.

@typing.final
def acquire(self) -> RESTClient:
289    @typing.final
290    def acquire(self) -> RESTClient:
291        """Acquires a new `RESTClient` instance from this pool.
292
293        Returns
294        -------
295        `RESTClient`
296            An instance of a `RESTClient`.
297        """
298        return RESTClient(
299            self._token,
300            client_secret=self._client_secret,
301            client_id=self._client_id,
302            loads=self._loads,
303            dumps=self._dumps,
304            max_retries=self._max_retries,
305            debug=self._enable_debug,
306            client_session=self._client_session,
307        )

Acquires a new RESTClient instance from this pool.

Returns
@typing.final
class Race(builtins.int, aiobungie.Enum):
485@typing.final
486class Race(int, Enum):
487    """An Enum for Destiny races."""
488
489    HUMAN = 0
490    AWOKEN = 1
491    EXO = 2
492    UNKNOWN = 3

An Enum for Destiny races.

HUMAN = <Race.HUMAN: 0>
AWOKEN = <Race.AWOKEN: 1>
EXO = <Race.EXO: 2>
UNKNOWN = <Race.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Raid(builtins.int, aiobungie.Enum):
132@typing.final
133class Raid(int, Enum):
134    """An Enum for all available raids in Destiny 2."""
135
136    DSC = 910380154
137    """Deep Stone Crypt"""
138
139    LW = 2122313384
140    """Last Wish"""
141
142    VOG = 3881495763
143    """Normal Valut of Glass"""
144
145    GOS = 3458480158
146    """Garden Of Salvation"""

An Enum for all available raids in Destiny 2.

DSC = <Raid.DSC: 910380154>

Deep Stone Crypt

LW = <Raid.LW: 2122313384>

Last Wish

VOG = <Raid.VOG: 3881495763>

Normal Valut of Glass

GOS = <Raid.GOS: 3458480158>

Garden Of Salvation

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class RateLimitedError(aiobungie.HTTPError):
250@attrs.define(auto_exc=True)
251class RateLimitedError(HTTPError):
252    """Raised when too many request status code is returned."""
253
254    http_status: http.HTTPStatus = attrs.field(
255        default=http.HTTPStatus.TOO_MANY_REQUESTS, init=False
256    )
257    """The request response http status."""
258
259    url: typedefs.StrOrURL
260    """The URL/endpoint caused this error."""
261
262    body: typing.Any
263    """The response body."""
264
265    retry_after: float = attrs.field(default=0.0)
266    """The amount of seconds you need to wait before retrying to requests."""
267
268    message: str = attrs.field(init=False)
269    """A Bungie human readable message describes the cause of the error."""
270
271    # Type Ignore: attrs provide a `.default` setter on its attribs to allow
272    # changing the default value.
273    @message.default  # pyright: ignore
274    def _(self) -> str:
275        return f"You're ratelimited for {self.retry_after}, Endpoint: {self.url}. Slow down!"
276
277    def __str__(self) -> str:
278        return self.message

Raised when too many request status code is returned.

RateLimitedError(url: Union[str, yarl.URL], body: Any, retry_after: float = 0.0)
2def __init__(self, url, body, retry_after=attr_dict['retry_after'].default):
3    self.http_status = attr_dict['http_status'].default
4    self.url = url
5    self.body = body
6    self.retry_after = retry_after
7    self.message = __attr_factory_message(self)
8    BaseException.__init__(self, self.url,self.body,self.retry_after)

Method generated by attrs for class RateLimitedError.

http_status: http.HTTPStatus

The request response http status.

url: Union[str, yarl.URL]

The URL/endpoint caused this error.

body: Any

The response body.

retry_after: float

The amount of seconds you need to wait before retrying to requests.

message: str

A Bungie human readable message describes the cause of the error.

Inherited Members
builtins.BaseException
with_traceback
add_note
args
@typing.final
class RecordState(aiobungie.Flag):
50@typing.final
51class RecordState(enums.Flag):
52    """An enum for records component states."""
53
54    NONE = 0
55    REDEEMED = 1 << 0
56    UNAVAILABLE = 1 << 1
57    OBJECTIVE_NOT_COMPLETED = 1 << 2
58    OBSCURED = 1 << 3
59    INVISIBLE = 1 << 4
60    ENTITLEMENT_UNOWNED = 1 << 5
61    CAN_EQUIP_TITLE = 1 << 6

An enum for records component states.

NONE = <RecordState.NONE: 0>
REDEEMED = <RecordState.REDEEMED: 1>
UNAVAILABLE = <RecordState.UNAVAILABLE: 2>
OBJECTIVE_NOT_COMPLETED = <RecordState.OBJECTIVE_NOT_COMPLETED: 4>
OBSCURED = <RecordState.OBSCURED: 8>
INVISIBLE = <RecordState.INVISIBLE: 16>
ENTITLEMENT_UNOWNED = <RecordState.ENTITLEMENT_UNOWNED: 32>
CAN_EQUIP_TITLE = <RecordState.CAN_EQUIP_TITLE: 64>
Inherited Members
Flag
name
value
@typing.final
class Relationship(builtins.int, aiobungie.Enum):
680@typing.final
681class Relationship(int, Enum):
682    """An enum for bungie friends relationship types."""
683
684    UNKNOWN = 0
685    FRIEND = 1
686    INCOMING_REQUEST = 2
687    OUTGOING_REQUEST = 3

An enum for bungie friends relationship types.

UNKNOWN = <Relationship.UNKNOWN: 0>
FRIEND = <Relationship.FRIEND: 1>
INCOMING_REQUEST = <Relationship.INCOMING_REQUEST: 2>
OUTGOING_REQUEST = <Relationship.OUTGOING_REQUEST: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class ResponseError(aiobungie.HTTPException):
245@attrs.define(auto_exc=True)
246class ResponseError(HTTPException):
247    """Exception for other HTTP response errors."""

Exception for other HTTP response errors.

ResponseError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class ResponseError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
add_note
args
@typing.final
class Stat(builtins.int, aiobungie.Enum):
507@typing.final
508class Stat(int, Enum):
509    """An Enum for Destiny 2 character stats."""
510
511    NONE = 0
512    MOBILITY = 2996146975
513    RESILIENCE = 392767087
514    RECOVERY = 1943323491
515    DISCIPLINE = 1735777505
516    INTELLECT = 144602215
517    STRENGTH = 4244567218
518    LIGHT_POWER = 1935470627

An Enum for Destiny 2 character stats.

NONE = <Stat.NONE: 0>
MOBILITY = <Stat.MOBILITY: 2996146975>
RESILIENCE = <Stat.RESILIENCE: 392767087>
RECOVERY = <Stat.RECOVERY: 1943323491>
DISCIPLINE = <Stat.DISCIPLINE: 1735777505>
INTELLECT = <Stat.INTELLECT: 144602215>
STRENGTH = <Stat.STRENGTH: 4244567218>
LIGHT_POWER = <Stat.LIGHT_POWER: 1935470627>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
TRACE = 5
@typing.final
class TierType(builtins.int, aiobungie.Enum):
622@typing.final
623class TierType(int, Enum):
624    """An enum for a Destiny 2 item tier type."""
625
626    UNKNOWN = 0
627    CURRENCY = 1
628    BASIC = 2
629    COMMON = 3
630    RARE = 4
631    SUPERIOR = 5
632    EXOTIC = 6

An enum for a Destiny 2 item tier type.

UNKNOWN = <TierType.UNKNOWN: 0>
CURRENCY = <TierType.CURRENCY: 1>
BASIC = <TierType.BASIC: 2>
COMMON = <TierType.COMMON: 3>
RARE = <TierType.RARE: 4>
SUPERIOR = <TierType.SUPERIOR: 5>
EXOTIC = <TierType.EXOTIC: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class TransferStatus(aiobungie.Flag):
732@typing.final
733class TransferStatus(Flag):
734    """An enum for items transfer statuses."""
735
736    CAN_TRANSFER = 0
737    """The item can be transferred."""
738    IS_EQUIPPED = 1 << 0
739    """You can't transfer since the item is equipped."""
740    NOT_TRASNFERRABLE = 1 << 1
741    """This item can not be transferred."""
742    COULD_BE_TRANSFERRED = 1 << 2
743    """You can transfer the item. But the place you're trying to put it at has no space for it."""

An enum for items transfer statuses.

CAN_TRANSFER = <TransferStatus.CAN_TRANSFER: 0>

The item can be transferred.

IS_EQUIPPED = <TransferStatus.IS_EQUIPPED: 1>

You can't transfer since the item is equipped.

NOT_TRASNFERRABLE = <TransferStatus.NOT_TRASNFERRABLE: 2>

This item can not be transferred.

COULD_BE_TRANSFERRED = <TransferStatus.COULD_BE_TRANSFERRED: 4>

You can transfer the item. But the place you're trying to put it at has no space for it.

Inherited Members
Flag
name
value
@attrs.define(auto_exc=True)
class Unauthorized(aiobungie.HTTPException):
154@attrs.define(auto_exc=True)
155class Unauthorized(HTTPException):
156    """An exception that's raised when trying to make unauthorized call to a resource and it returns 404."""
157
158    http_status: http.HTTPStatus = attrs.field(
159        default=http.HTTPStatus.UNAUTHORIZED, init=False
160    )

An exception that's raised when trying to make unauthorized call to a resource and it returns 404.

Unauthorized( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Unauthorized.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
add_note
args
@typing.final
class ValueUIStyle(builtins.int, aiobungie.Enum):
74@typing.final
75class ValueUIStyle(int, enums.Enum):
76    AUTOMATIC = 0
77    FRACTION = 1
78    CHECK_BOX = 2
79    PERCENTAGE = 3
80    DATETIME = 4
81    FRACTION_FLOAT = 5
82    INTEGER = 6
83    TIME_DURATION = 7
84    HIDDEN = 8
85    MULTIPLIER = 9
86    GREEN_PIPS = 10
87    RED_PIPS = 11
88    EXPLICIT_PERCENTAGE = 12
89    RAW_FLOAT = 13
90    LEVEL_AND_REWARD = 14

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by '+' or '-' and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal.

>>> int('0b100', base=0)
4
AUTOMATIC = <ValueUIStyle.AUTOMATIC: 0>
FRACTION = <ValueUIStyle.FRACTION: 1>
CHECK_BOX = <ValueUIStyle.CHECK_BOX: 2>
PERCENTAGE = <ValueUIStyle.PERCENTAGE: 3>
DATETIME = <ValueUIStyle.DATETIME: 4>
FRACTION_FLOAT = <ValueUIStyle.FRACTION_FLOAT: 5>
INTEGER = <ValueUIStyle.INTEGER: 6>
TIME_DURATION = <ValueUIStyle.TIME_DURATION: 7>
HIDDEN = <ValueUIStyle.HIDDEN: 8>
MULTIPLIER = <ValueUIStyle.MULTIPLIER: 9>
GREEN_PIPS = <ValueUIStyle.GREEN_PIPS: 10>
RED_PIPS = <ValueUIStyle.RED_PIPS: 11>
EXPLICIT_PERCENTAGE = <ValueUIStyle.EXPLICIT_PERCENTAGE: 12>
RAW_FLOAT = <ValueUIStyle.RAW_FLOAT: 13>
LEVEL_AND_REWARD = <ValueUIStyle.LEVEL_AND_REWARD: 14>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Vendor(builtins.int, aiobungie.Enum):
229@typing.final
230class Vendor(int, Enum):
231    """An Enum for all available vendors in Destiny 2."""
232
233    ZAVALA = 69482069
234    XUR = 2190858386
235    BANSHE = 672118013
236    SPIDER = 863940356
237    SHAXX = 3603221665
238    KADI = 529635856
239    """Postmaster exo."""
240    YUNA = 1796504621
241    """Asia servers only."""
242    EVERVERSE = 3361454721
243    AMANDA = 460529231
244    """Amanda holiday"""
245    CROW = 3611983588
246    HAWTHORNE = 3347378076
247    ADA1 = 350061650
248    DRIFTER = 248695599
249    IKORA = 1976548992
250    SAINT = 765357505
251    """Saint-14"""
252    ERIS_MORN = 1616085565
253    SHAW_HAWN = 1816541247
254    """COSMODROME Guy"""
255    VARIKS = 2531198101

An Enum for all available vendors in Destiny 2.

ZAVALA = <Vendor.ZAVALA: 69482069>
XUR = <Vendor.XUR: 2190858386>
BANSHE = <Vendor.BANSHE: 672118013>
SPIDER = <Vendor.SPIDER: 863940356>
SHAXX = <Vendor.SHAXX: 3603221665>
KADI = <Vendor.KADI: 529635856>

Postmaster exo.

YUNA = <Vendor.YUNA: 1796504621>

Asia servers only.

EVERVERSE = <Vendor.EVERVERSE: 3361454721>
AMANDA = <Vendor.AMANDA: 460529231>

Amanda holiday

CROW = <Vendor.CROW: 3611983588>
HAWTHORNE = <Vendor.HAWTHORNE: 3347378076>
ADA1 = <Vendor.ADA1: 350061650>
DRIFTER = <Vendor.DRIFTER: 248695599>
IKORA = <Vendor.IKORA: 1976548992>
SAINT = <Vendor.SAINT: 765357505>

Saint-14

ERIS_MORN = <Vendor.ERIS_MORN: 1616085565>
SHAW_HAWN = <Vendor.SHAW_HAWN: 1816541247>

COSMODROME Guy

VARIKS = <Vendor.VARIKS: 2531198101>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class WeaponType(builtins.int, aiobungie.Enum):
521@typing.final
522class WeaponType(int, Enum):
523    """Enums for The three Destiny Weapon Types"""
524
525    NONE = 0
526    KINETIC = 1498876634
527    ENERGY = 2465295065
528    POWER = 953998645

Enums for The three Destiny Weapon Types

NONE = <WeaponType.NONE: 0>
KINETIC = <WeaponType.KINETIC: 1498876634>
ENERGY = <WeaponType.ENERGY: 2465295065>
POWER = <WeaponType.POWER: 953998645>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
annotations = _Feature((3, 7, 0, 'beta', 1), None, 16777216)
def iter( iterable: collections.abc.Iterable[~Item]) -> Iterator[~Item]:
614def iter(
615    iterable: collections.Iterable[Item],
616) -> Iterator[Item]:
617    """Transform an iterable into an flat iterator.
618
619    Example
620    -------
621    ```py
622    sequence = (1,2,3)
623    for item in aiobungie.iter(sequence).reversed():
624        print(item)
625    # 3
626    # 2
627    # 1
628    ```
629
630    Parameters
631    ----------
632    iterable: `typing.Iterable[Item]`
633        The iterable to convert.
634
635    Raises
636    ------
637    `StopIteration`
638        If no elements are left in the iterator.
639    """
640    return Iterator(iterable)

Transform an iterable into an flat iterator.

Example
sequence = (1,2,3)
for item in aiobungie.iter(sequence).reversed():
    print(item)
# 3
# 2
# 1
Parameters
  • iterable (typing.Iterable[Item]): The iterable to convert.
Raises
  • StopIteration: If no elements are left in the iterator.
async def panic( response: aiohttp.client_reqrep.ClientResponse) -> HTTPError:
281async def panic(response: aiohttp.ClientResponse) -> HTTPError:
282    """Immediately raise an exception based on the response."""
283
284    # Bungie get funky and return HTML instead of JSON when making an authorized
285    # request with a dummy access token. We could technically read the page content
286    # but that's Bungie's fault for not returning a JSON response.
287    if response.content_type != "application/json":
288        raise HTTPError(
289            message=f"Expected JSON response, Got {response.content_type}, "
290            f"{response.real_url.human_repr()}",
291            http_status=http.HTTPStatus(response.status),
292        )
293
294    body: collections.Mapping[str, typing.Any] = helpers.loads(await response.read())  # type: ignore
295    message: str = body.get("Message", "UNDEFINED_MESSAGE")
296    error_status: str = body.get("ErrorStatus", "UNDEFINED_ERROR_STATUS")
297    message_data: dict[str, str] = body.get("MessageData", {})
298    throttle_seconds: int = body.get("ThrottleSeconds", 0)
299    error_code: int = body.get("ErrorCode", 0)
300
301    # Standard HTTP status.
302    match response.status:
303        case http.HTTPStatus.NOT_FOUND:
304            return NotFound(
305                message=message,
306                error_code=error_code,
307                throttle_seconds=throttle_seconds,
308                url=str(response.real_url),
309                body=body,
310                headers=response.headers,
311                error_status=error_status,
312                message_data=message_data,
313            )
314
315        case http.HTTPStatus.FORBIDDEN:
316            return Forbidden(
317                message=message,
318                error_code=error_code,
319                throttle_seconds=throttle_seconds,
320                url=str(response.real_url),
321                body=body,
322                headers=response.headers,
323                error_status=error_status,
324                message_data=message_data,
325            )
326
327        case http.HTTPStatus.UNAUTHORIZED:
328            return Unauthorized(
329                message=message,
330                error_code=error_code,
331                throttle_seconds=throttle_seconds,
332                url=str(response.real_url),
333                body=body,
334                headers=response.headers,
335                error_status=error_status,
336                message_data=message_data,
337            )
338
339        case http.HTTPStatus.BAD_REQUEST:
340            # Membership needs to be alone.
341            if error_status == "InvalidParameters":
342                return MembershipTypeError(
343                    message=message,
344                    body=body,
345                    headers=response.headers,
346                    url=str(response.url),
347                    membership_type=message_data["membershipType"],
348                    required_membership=message_data["membershipInfo.membershipType"],
349                    membership_id=int(message_data["membershipId"]),
350                )
351            return BadRequest(
352                message=message,
353                body=body,
354                headers=response.headers,
355                url=str(response.url),
356            )
357        case _:
358            status = http.HTTPStatus(response.status)
359
360            if 400 <= status < 500:
361                return ResponseError(
362                    message=message,
363                    error_code=error_code,
364                    throttle_seconds=throttle_seconds,
365                    url=str(response.real_url),
366                    body=body,
367                    headers=response.headers,
368                    error_status=error_status,
369                    message_data=message_data,
370                    http_status=status,
371                )
372
373            # Need to self handle ~5xx errors
374            elif 500 <= status < 600:
375                # No API key or method requires OAuth2 most likely.
376                if error_status in {
377                    "ApiKeyMissingFromRequest",
378                    "WebAuthRequired",
379                    "ApiInvalidOrExpiredKey",
380                    "AuthenticationInvalid",
381                    "AuthorizationCodeInvalid",
382                }:
383                    return Unauthorized(
384                        message=message,
385                        error_code=error_code,
386                        throttle_seconds=throttle_seconds,
387                        url=str(response.real_url),
388                        body=body,
389                        headers=response.headers,
390                        error_status=error_status,
391                        message_data=message_data,
392                    )
393
394                # Anything contains not found.
395                elif (
396                    "NotFound" in error_status
397                    or error_status == "UserCannotFindRequestedUser"
398                ):
399                    return NotFound(
400                        message=message,
401                        error_code=error_code,
402                        throttle_seconds=throttle_seconds,
403                        url=str(response.real_url),
404                        body=body,
405                        headers=response.headers,
406                        error_status=error_status,
407                        message_data=message_data,
408                    )
409
410                # Other 5xx errors.
411                else:
412                    return InternalServerError(
413                        message=message,
414                        error_code=error_code,
415                        throttle_seconds=throttle_seconds,
416                        url=str(response.real_url),
417                        body=body,
418                        headers=response.headers,
419                        error_status=error_status,
420                        message_data=message_data,
421                        http_status=status,
422                    )
423            # Something else.
424            else:
425                return HTTPException(
426                    message=message,
427                    error_code=error_code,
428                    throttle_seconds=throttle_seconds,
429                    url=str(response.real_url),
430                    body=body,
431                    headers=response.headers,
432                    error_status=error_status,
433                    message_data=message_data,
434                    http_status=status,
435                )

Immediately raise an exception based on the response.

def stringify_headers(headers: collections.abc.Mapping[str, typing.Any]) -> str:
438def stringify_headers(headers: collections.Mapping[str, typing.Any]) -> str:
439    return (
440        "{ \n"
441        + "\n".join(  # noqa: W503
442            f"{f'   {key}'}: {value}"
443            if key
444            not in {
445                "Authorization",
446                "X-API-KEY",
447                "client_secret",
448                "client_id",
449                "access_token",
450                "refresh_token",
451            }
452            else f"   {key}: REDACTED_TOKEN"
453            for key, value in headers.items()
454        )
455        + "\n}"  # noqa: W503
456    )